/// <summary> /// Applied before RefreshRows runs. /// </summary> internal static bool Prefix(TableScreen __instance) { var identities = HashSetPool<IAssignableIdentity, TableScreen>.Allocate(); var living = Components.LiveMinionIdentities.Items; StoredMinionIdentity smi; // Living Duplicants for (int i = 0; i < living.Count; i++) { var dupe = living[i]; if (dupe != null) identities.Add(dupe); } // Duplicants in vanilla rockets and similar foreach (var minionStorage in Components.MinionStorages.Items) foreach (var info in minionStorage.GetStoredMinionInfo()) { var dupe = info.serializedMinion; if (dupe != null && (smi = dupe.Get<StoredMinionIdentity>()) != null) __instance.AddRow(smi); } ClearAndAddRows(__instance, identities); // Add the missing rows foreach (var missingMinion in identities) __instance.AddRow(missingMinion); identities.Recycle(); if (DlcManager.FeatureClusterSpaceEnabled()) AddDividers(__instance); SortRows(__instance); __instance.rows_dirty = false; return false; }
private void ImportTables(Department department) { var fileName = string.Format("{0}/Imports/table{1}.txt", LocalSettings.AppPath, "_" + LocalSettings.CurrentLanguage); if (!File.Exists(fileName)) { fileName = string.Format("{0}/Imports/table.txt", LocalSettings.AppPath); } if (!File.Exists(fileName)) { return; } var lines = File.ReadAllLines(fileName); var items = BatchCreateTables(lines, _workspace); _workspace.CommitChanges(); var screen = new TableScreen { Name = Resources.AllTables, ColumnCount = 8 }; _workspace.Add(screen); foreach (var table in items) { screen.AddScreenItem(table); } _workspace.CommitChanges(); department.TableScreenId = screen.Id; }
/// <summary> /// Sorts the table's rows. /// </summary> /// <param name="instance">The table screen to sort.</param> private static void SortRows(TableScreen instance) { var rows = instance.all_sortable_rows; bool reversed = instance.sort_is_reversed; var comparison = new TableSortComparison(instance.active_sort_method, reversed); var dividerIndices = DictionaryPool<int, int, TableScreen>.Allocate(); var dupesByWorld = DictionaryPool<int, TableRowList.PooledList, TableScreen>. Allocate(); int index = 0; var entryList = instance.scroll_content_transform; UpdateHeaders(instance, reversed); GroupDupesByWorld(rows, dupesByWorld); rows.Clear(); foreach (var pair in dupesByWorld) { var list = pair.Value; // 1 offset for the item added plus the number of items in this list dividerIndices.Add(pair.Key, index); index++; if (comparison.IsSortable) list.Sort(comparison); index += list.Count; rows.AddRange(list); list.Recycle(); } dupesByWorld.Recycle(); MoveRows(instance, rows, dividerIndices); dividerIndices.Recycle(); // Schedule a freeze if (entryList != null && instance.isActiveAndEnabled) instance.StartCoroutine(FreezeLayouts(rows)); }
/// <summary> /// Adds dividers for each planetoid in the Spaced Out DLC. /// </summary> /// <param name="instance">The table screen to update.</param> private static void AddDividers(TableScreen instance) { GameObject target; int id; var occupiedWorlds = DictionaryPool<int, WorldContainer, TableScreen>.Allocate(); foreach (int worldId in ClusterManager.Instance.GetWorldIDsSorted()) instance.AddWorldDivider(worldId); // List occupied planets foreach (object obj in Components.MinionAssignablesProxy) if (obj is MinionAssignablesProxy proxy && proxy != null && (target = proxy. GetTargetGameObject()) != null) { var world = target.GetMyWorld(); if (world != null && !occupiedWorlds.ContainsKey(id = world.id)) occupiedWorlds.Add(id, world); } foreach (var pair in instance.worldDividers) if (pair.Value.TryGetComponent(out HierarchyReferences hr)) { var dividerRow = hr.GetReference("NobodyRow"); id = pair.Key; if (occupiedWorlds.TryGetValue(id, out WorldContainer world)) { dividerRow.gameObject.SetActive(false); pair.Value.SetActive(world.IsDiscovered); } else { dividerRow.gameObject.SetActive(true); pair.Value.SetActive(ClusterManager.Instance.GetWorld(id).IsDiscovered); } } occupiedWorlds.Recycle(); }
/// <summary> /// Configures the scroll bars for each row. /// </summary> /// <param name="row">The row being configured.</param> /// <param name="parent">The parent game object of the table row.</param> /// <param name="id">The scroller ID to look up.</param> /// <param name="widget">The widget to display in this row.</param> /// <param name="screen">The parent table screen.</param> private static void ConfigureScroller(TableRow row, GameObject parent, string id, GameObject widget, TableScreen screen) { Transform content; ScrollRect sr; var scrollers = row.scrollers; if (scrollers.TryGetValue(id, out GameObject scrollerGO)) { content = scrollerGO.transform; if (content.parent.TryGetComponent(out sr)) sr.horizontalNormalizedPosition = 0.0f; widget.transform.SetParent(content); } else { var prefab = Util.KInstantiateUI(row.scrollerPrefab, parent, true); if (prefab.TryGetComponent(out sr)) { content = sr.content; sr.onValueChanged.AddListener(new ScrollListener(screen, sr). OnScroll); scrollers.Add(id, content.gameObject); // Is it a border? var border = content.parent.Find("Border"); if (border != null) row.scrollerBorders.Add(id, border.gameObject); sr.horizontalNormalizedPosition = 0.0f; widget.transform.SetParent(content); } } }
/// <summary> /// Configures the row's content, only adding widgets that are new. /// </summary> /// <param name="row">The row being configured.</param> /// <param name="minion">The Duplicant for this row.</param> /// <param name="columns">The columns to display.</param> /// <param name="screen">The parent table screen.</param> private static void ConfigureContent(TableRow row, IAssignableIdentity minion, IDictionary<string, TableColumn> columns, TableScreen screen) { bool def = row.isDefault; var go = row.gameObject; row.minion = minion; ConfigureImage(row, minion); foreach (var pair in columns) { var column = pair.Value; var widgets = row.widgets; string id = column.scrollerID; // Columns cannot be deleted in vanilla if (!widgets.TryGetValue(column, out GameObject widget)) { // Create a new one if (minion == null) { if (def) widget = column.GetDefaultWidget(go); else widget = column.GetHeaderWidget(go); } else widget = column.GetMinionWidget(go); widgets.Add(column, widget); column.widgets_by_row.Add(row, widget); } // Update the scroller if needed if (!string.IsNullOrEmpty(id) && column.screen.column_scrollers.Contains(id)) ConfigureScroller(row, go, id, widget, screen); } // Run events after the update is complete foreach (var pair in columns) { var column = pair.Value; if (column.widgets_by_row.TryGetValue(row, out GameObject widget)) { string id = column.scrollerID; column.on_load_action?.Invoke(minion, widget); // Apparently the order just... works out? <shrug> } } if (minion != null) go.name = minion.GetProperName(); else if (def) go.name = "defaultRow"; // "Click to go to Duplicant" if (row.selectMinionButton != null) row.selectMinionButton.transform.SetAsLastSibling(); // Update the border sizes foreach (var pair in row.scrollerBorders) { var border = pair.Value; var rt = border.rectTransform(); float width = rt.rect.width; border.transform.SetParent(go.transform); rt.anchorMin = rt.anchorMax = Vector2.up; rt.sizeDelta = new Vector2(width, 374.0f); var scrollRT = row.scrollers[pair.Key].transform.parent.rectTransform(); Vector3 a = scrollRT.GetLocalPosition(); a.x -= scrollRT.sizeDelta.x * 0.5f; a.y = rt.GetLocalPosition().y - rt.anchoredPosition.y; rt.SetLocalPosition(a); } }
/// <summary> /// Removes and pools any existing rows. Leaves the default and header row if present, /// otherwise creates and adds one when requested. /// </summary> /// <param name="instance">The table screen to clear.</param> /// <param name="toAdd">The Duplicants to be added or updated.</param> private static void ClearAndAddRows(TableScreen instance, ISet<IAssignableIdentity> toAdd) { var columns = instance.columns; var hr = instance.header_row; List<TableRow> rows = instance.rows, sortableRows = instance.all_sortable_rows; int n = rows.Count; TableRow defaultRow = null, headerRow = null; var newRows = TableRowList.Allocate(); var deadRows = HashSetPool<TableRow, TableScreen>.Allocate(); IAssignableIdentity minion; for (int i = 0; i < n; i++) { var row = rows[i]; var go = row.gameObject; // Do not destroy the default or header; pull out any rows for existing minion // identities if (row.rowType == TableRow.RowType.Default) { ThawLayout(go); defaultRow = row; } else if (go == hr && hr != null) { ThawLayout(go); headerRow = row; } else if (row.rowType != TableRow.RowType.WorldDivider && (minion = row. minion) != null && toAdd.Remove(minion)) { ThawLayout(go); ConfigureContent(row, minion, columns, instance); newRows.Add(row); } else deadRows.Add(row); } sortableRows.Clear(); rows.Clear(); // Restore cached default and header rows; header first if (headerRow != null) { ConfigureContent(headerRow, null, columns, instance); rows.Add(headerRow); } else instance.AddRow(null); if (defaultRow != null) { ConfigureContent(defaultRow, null, columns, instance); rows.Add(defaultRow); } else if (instance.has_default_duplicant_row) instance.AddDefaultRow(); // Add reused rows, delete removed rows sortableRows.AddRange(newRows); rows.AddRange(newRows); newRows.Recycle(); TakeOutTrash(instance, deadRows); deadRows.Recycle(); }
/// <summary> /// Moves the rows and row dividers into their final positions. /// </summary> /// <param name="instance">The table screen to update.</param> /// <param name="rows">The current row list with sorting.</param> /// <param name="dividerIndices">The locations of each world divider.</param> private static void MoveRows(TableScreen instance, IList<TableRow> rows, IDictionary<int, int> dividerIndices) { int n = rows.Count; var dividers = instance.worldDividers; // Sort the rows in the UI for (int i = 0; i < n; i++) rows[i].transform.SetSiblingIndex(i); foreach (var pair in dividerIndices) if (dividers.TryGetValue(pair.Key, out GameObject divider)) // Will not be present in vanilla divider.transform.SetSiblingIndex(pair.Value); // Move the default row to the beginning if (instance.has_default_duplicant_row) instance.default_row.transform.SetAsFirstSibling(); }
/// <summary> /// Updates the header states to match the sorting state. /// </summary> /// <param name="instance">The table screen to update.</param> /// <param name="reverse">Whether the sorting order is reversed.</param> private static void UpdateHeaders(TableScreen instance, bool reverse) { var sortColumn = instance.active_sort_column; MultiToggle sortToggle; foreach (var pair in instance.columns) { var tableColumn = pair.Value; if (tableColumn != null && (sortToggle = tableColumn.column_sort_toggle) != null) { int state = sortToggle.CurrentState; if (tableColumn == sortColumn) { if (reverse) { if (state != 2) sortToggle.ChangeState(2); } else if (state != 1) sortToggle.ChangeState(1); } else if (state != 0) sortToggle.ChangeState(0); } } }
/// <summary> /// Disposes and removes the specified rows from the table screen. /// </summary> /// <param name="instance">The table screen to clean up.</param> /// <param name="deadRows">The rows that were removed.</param> private static void TakeOutTrash(TableScreen instance, ICollection<TableRow> deadRows) { var ikr = instance.known_widget_rows; // Avoid leaking dead rows var deadWidgets = ListPool<GameObject, TableScreen>.Allocate(); foreach (var pair in ikr) if (deadRows.Contains(pair.Value)) deadWidgets.Add(pair.Key); int n = deadWidgets.Count; for (int i = 0; i < n; i++) ikr.Remove(deadWidgets[i]); deadWidgets.Recycle(); foreach (var row in deadRows) row.Clear(); // Dividers are fairly cheap, destroy and recreate them is easier var dividers = instance.worldDividers; foreach (var pair in dividers) Util.KDestroyGameObject(pair.Value); dividers.Clear(); }
public void UpdateTableData(TableScreen selectedTableScreen, int pageNo) { var set = selectedTableScreen.Tables.Select(x => x.Id); if (selectedTableScreen.PageCount > 1) { set = selectedTableScreen.Tables .OrderBy(x => x.Order) .Skip(pageNo * selectedTableScreen.ItemCountPerPage) .Take(selectedTableScreen.ItemCountPerPage) .Select(x => x.Id); } var result = Dao.Select <Table, dynamic>(x => new { x.Id, Tid = x.TicketId, Locked = x.IsTicketLocked }, x => set.Contains(x.Id)); foreach (var td in result) { var tid = td.Id; var table = selectedTableScreen.Tables.Single(x => x.Id == tid); table.TicketId = td.Tid; table.IsTicketLocked = td.Locked; } }
public ScrollListener(TableScreen screen, ScrollRect scrollRect) { this.screen = screen; this.scrollRect = scrollRect; }
/// <summary> /// Applied before SortRows runs. /// </summary> internal static bool Prefix(TableScreen __instance) { SortRows(__instance); return false; }
public TableScreenItemViewModel(Table model, TableScreen screen) : this(model, screen, null) { }
/// <summary> /// Applied before ConfigureContent runs. /// </summary> internal static bool Prefix(TableRow __instance, IAssignableIdentity minion, Dictionary<string, TableColumn> columns, TableScreen screen) { ConfigureContent(__instance, minion, columns, screen); return false; }
public TableScreenItemViewModel(Table model, TableScreen screen, ICommand actionCommand) { _actionCommand = actionCommand; _screen = screen; Model = model; }
private void OnSelectTableCategoryExecuted(TableScreen obj) { UpdateTables(obj.Id); }