diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 06:15:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 06:15:40 +0000 |
commit | a7253052777df3bcf4b2abe9367de244cbc35da1 (patch) | |
tree | 1168b662d8028f172d12c2eb4efc62bf8408434b /extensions/46/vertical-workspaces/lib/iconGrid.js | |
parent | Adding upstream version 20231210. (diff) | |
download | gnome-shell-extensions-extra-a7253052777df3bcf4b2abe9367de244cbc35da1.tar.xz gnome-shell-extensions-extra-a7253052777df3bcf4b2abe9367de244cbc35da1.zip |
Adding upstream version 20240414.upstream/20240414upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions/46/vertical-workspaces/lib/iconGrid.js')
-rw-r--r-- | extensions/46/vertical-workspaces/lib/iconGrid.js | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/extensions/46/vertical-workspaces/lib/iconGrid.js b/extensions/46/vertical-workspaces/lib/iconGrid.js new file mode 100644 index 0000000..87f6adb --- /dev/null +++ b/extensions/46/vertical-workspaces/lib/iconGrid.js @@ -0,0 +1,346 @@ +/** + * V-Shell (Vertical Workspaces) + * iconGrid.js + * + * @author GdH <G-dH@github.com> + * @copyright 2022 - 2024 + * @license GPL-3.0 + * + */ + +'use strict'; + +import St from 'gi://St'; + +import * as IconGrid from 'resource:///org/gnome/shell/ui/iconGrid.js'; + +let Me; +let opt; + +// added sizes for better scaling +const IconSize = { + LARGEST: 256, + 224: 224, + 208: 208, + 192: 192, + 176: 176, + 160: 160, + 144: 144, + 128: 128, + 112: 112, + LARGE: 96, + 80: 80, + 64: 64, + TINY: 48, +}; + +const PAGE_WIDTH_CORRECTION = 100; + +export const IconGridModule = class { + constructor(me) { + Me = me; + opt = Me.opt; + + this._firstActivation = true; + this.moduleEnabled = false; + this._overrides = null; + } + + cleanGlobals() { + Me = null; + opt = null; + } + + update(reset) { + this.moduleEnabled = opt.get('appDisplayModule'); + // if notifications are enabled no override is needed + reset = reset || !this.moduleEnabled; + + // don't touch original code if module disabled + if (reset && !this._firstActivation) { + this._disableModule(); + } else if (!reset) { + this._firstActivation = false; + this._activateModule(); + } + } + + _activateModule() { + if (!this._overrides) + this._overrides = new Me.Util.Overrides(); + + this._overrides.addOverride('IconGrid', IconGrid.IconGrid.prototype, IconGridCommon); + this._overrides.addOverride('IconGridLayout', IconGrid.IconGridLayout.prototype, IconGridLayoutCommon); + } + + _disableModule() { + if (this._overrides) + this._overrides.removeAll(); + this._overrides = null; + } +}; + +const IconGridCommon = { + getItemsAtPage(page) { + if (page < 0 || page >= this.nPages) + return []; + // throw new Error(`Page ${page} does not exist at IconGrid`); + + const layoutManager = this.layout_manager; + return layoutManager.getItemsAtPage(page); + }, + + _findBestModeForSize(width, height) { + // this function is for main grid only, folder grid calculation is in appDisplay.AppFolderDialog class + if (this._currentMode > -1 || this.layoutManager._isFolder) + return; + const { pagePadding } = this.layout_manager; + const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const iconPadding = 51 * scaleFactor; + // provided width is usually about 100px wider in horizontal orientation with prev/next page indicators + const pageIndicatorCompensation = opt.ORIENTATION ? 0 : PAGE_WIDTH_CORRECTION; + + width -= pagePadding.left + pagePadding.right + pageIndicatorCompensation; + width *= opt.APP_GRID_PAGE_WIDTH_SCALE; + height -= pagePadding.top + pagePadding.bottom; + + // store grid max dimensions for icon size algorithm + this.layoutManager._gridWidth = width; + this.layoutManager._gridHeight = height; + + width -= 80; // compensation for default padding + height -= 80; + + const spacing = opt.APP_GRID_SPACING; + // set the icon size as fixed to avoid changes in size later + const iconSize = opt.APP_GRID_ICON_SIZE > 0 ? opt.APP_GRID_ICON_SIZE : opt.APP_GRID_ICON_SIZE_DEFAULT; + // this.layout_manager.fixedIconSize = iconSize; + const itemSize = iconSize * scaleFactor + iconPadding; + // if this._gridModes.length === 1, custom grid should be used + // if (iconSize > 0 && this._gridModes.length > 1) { + let columns = opt.APP_GRID_COLUMNS; + let rows = opt.APP_GRID_ROWS; + // 0 means adaptive size + let unusedSpaceH = -1; + let unusedSpaceV = -1; + if (!columns) { + // calculate #columns + 1 without spacing + columns = Math.floor(width / itemSize) + 1; + // check if columns with spacing fits the available width + // and reduce the number until it fits + while (unusedSpaceH < 0) { + columns -= 1; + unusedSpaceH = width - columns * itemSize - (columns - 1) * spacing; + } + } + if (!rows) { + rows = Math.floor(height / itemSize) + 1; + while (unusedSpaceV < 0) { + rows -= 1; + unusedSpaceV = height - rows * itemSize - ((rows - 1) * spacing); + } + } + + this._gridModes = [{ columns, rows }]; + // } + + this._setGridMode(0); + }, +}; + +const IconGridLayoutCommon = { + _findBestIconSize() { + if (this.fixedIconSize !== -1) + return this.fixedIconSize; + + const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const nColumns = this.columnsPerPage; + const nRows = this.rowsPerPage; + + // if grid is not defined return default icon size + if (nColumns < 1 && nRows < 1) { + let iconSize; + if (this._isFolder) + iconSize = opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT; + else + iconSize = opt.APP_GRID_ICON_SIZE_DEFAULT; + + return iconSize; + } + + const columnSpacingPerPage = /* opt.APP_GRID_SPACING*/ 1 * (nColumns - 1); + const rowSpacingPerPage = /* opt.APP_GRID_SPACING*/ 1 * (nRows - 1); + const iconPadding = 55 * scaleFactor; + + const paddingH = this._isFolder ? this.pagePadding.left + this.pagePadding.right : 0; + const paddingV = this._isFolder ? this.pagePadding.top + this.pagePadding.bottom : 0; + + const width = this._gridWidth ? this._gridWidth : this._pageWidth; + const height = this._gridHeight ? this._gridHeight : this._pageHeight; + if (!width || !height) + return opt.APP_GRID_ICON_SIZE_DEFAULT; + + const [firstItem] = this._container; + + /* if (opt.APP_GRID_ADAPTIVE && !this._isFolder) + return opt.APP_GRID_ICON_SIZE_DEFAULT;*/ + + let iconSizes = Object.values(IconSize).sort((a, b) => b - a); + // limit max icon size for folders and fully adaptive folder grids, the whole range is for the main grid with active folders + if (this._isFolder && opt.APP_GRID_FOLDER_ADAPTIVE && opt.APP_GRID_FOLDER_ICON_SIZE < 0) + iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT), -1); + else if (this._isFolder) + iconSizes = iconSizes.slice(iconSizes.indexOf(IconSize.LARGE), -1); + else if (opt.APP_GRID_ADAPTIVE && opt.APP_GRID_ICON_SIZE < 0) + iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_ICON_SIZE_DEFAULT), -1); + + let sizeInvalid = false; + for (const size of iconSizes) { + let usedWidth, usedHeight; + + if (firstItem) { + firstItem.icon.setIconSize(size); + const [firstItemWidth] = firstItem.get_preferred_size(); + + const itemSize = firstItemWidth; + if (itemSize < size) + sizeInvalid = true; + + usedWidth = itemSize * nColumns; + usedHeight = itemSize * nRows; + } + + if (!firstItem || sizeInvalid) { + usedWidth = (size + iconPadding) * nColumns; + usedHeight = (size + iconPadding) * nRows; + } + const emptyHSpace = + width - usedWidth - columnSpacingPerPage - paddingH; + // this.pagePadding.left - this.pagePadding.right; + const emptyVSpace = + height - usedHeight - rowSpacingPerPage - paddingV; + // this.pagePadding.top - this.pagePadding.bottom; + + if (emptyHSpace >= 0 && emptyVSpace >= 0) { + return size; + } + } + + return IconSize.TINY; + }, + + removeItem(item) { + if (!this._items.has(item)) { + console.error(`iconGrid: Item ${item} is not part of the IconGridLayout`); + return; + // throw new Error(`Item ${item} is not part of the IconGridLayout`); + } + + if (!this._container) + return; + + this._shouldEaseItems = true; + + this._container.remove_child(item); + this._removeItemData(item); + }, + + addItem(item, page = -1, index = -1) { + if (this._items.has(item)) { + console.error(`iconGrid: Item ${item} already added to IconGridLayout`); + return; + // throw new Error(`Item ${item} already added to IconGridLayout`); + } + + if (page > this._pages.length) { + console.error(`iconGrid: Cannot add ${item} to page ${page}`); + page = -1; + index = -1; + // throw new Error(`Cannot add ${item} to page ${page}`); + } + + if (!this._container) + return; + + if (page !== -1 && index === -1) + page = this._findBestPageToAppend(page); + + this._shouldEaseItems = true; + this._container.add_child(item); + this._addItemToPage(item, page, index); + }, + + moveItem(item, newPage, newPosition) { + if (!this._items.has(item)) { + console.error(`iconGrid: Item ${item} is not part of the IconGridLayout`); + return; + // throw new Error(`Item ${item} is not part of the IconGridLayout`); + } + + this._shouldEaseItems = true; + + this._removeItemData(item); + + if (newPage !== -1 && newPosition === -1) + newPage = this._findBestPageToAppend(newPage); + this._addItemToPage(item, newPage, newPosition); + }, + + _addItemToPage(item, pageIndex, index) { + // Ensure we have at least one page + if (this._pages.length === 0) + this._appendPage(); + + // Append a new page if necessary + if (pageIndex === this._pages.length) + this._appendPage(); + + if (pageIndex >= this._pages.length) { + pageIndex = -1; + index = -1; + } + + if (pageIndex === -1) + pageIndex = this._pages.length - 1; + + if (index === -1) + index = this._pages[pageIndex].children.length; + + this._items.set(item, { + actor: item, + pageIndex, + destroyId: item.connect('destroy', () => this._removeItemData(item)), + visibleId: item.connect('notify::visible', () => { + const itemData = this._items.get(item); + + this._updateVisibleChildrenForPage(itemData.pageIndex); + + if (item.visible) + this._relocateSurplusItems(itemData.pageIndex); + else if (!this.allowIncompletePages) + this._fillItemVacancies(itemData.pageIndex); + }), + queueRelayoutId: item.connect('queue-relayout', () => { + this._childrenMaxSize = -1; + }), + }); + + item.icon.setIconSize(this._iconSize); + this._pages[pageIndex].children.splice(index, 0, item); + this._updateVisibleChildrenForPage(pageIndex); + this._relocateSurplusItems(pageIndex); + }, + + _findBestPageToAppend(startPage) { + const itemsPerPage = this.columnsPerPage * this.rowsPerPage; + + for (let i = startPage; i < this._pages.length; i++) { + const visibleItems = this._pages[i].visibleChildren; + + if (visibleItems.length < itemsPerPage) + return i; + } + + return this._pages.length; + }, +}; |