From 46b403cd0d9f31b2df7cfcbcda088f208aa3d2d4 Mon Sep 17 00:00:00 2001 From: lumix Date: Fri, 27 Dec 2024 12:07:07 +0800 Subject: [PATCH] fix: better disable selection ---> transparent selection (#4372) --- packages/core/src/facade/f-usermanager.ts | 3 +- .../core/src/services/theme/theme.service.ts | 6 +- .../crosshair-highlight.render-controller.ts | 8 +- .../src/controllers/prompt.controller.ts | 15 ++-- .../ref-selections.render-service.ts | 12 ++- .../range-selector/hooks/useRefactorEffect.ts | 8 +- packages/sheets-ui/src/facade/f-workbook.ts | 69 ++++++++++++++- packages/sheets-ui/src/facade/f-worksheet.ts | 28 +------ .../base-selection-render.service.ts | 60 +++++++++---- .../mobile-selection-render.service.ts | 12 +-- .../selection/selection-render.service.ts | 84 ++++++++++++++----- .../commands/utils/selection-command-util.ts | 6 +- packages/sheets/src/facade/f-range.ts | 5 +- packages/sheets/src/facade/f-worksheet.ts | 1 + packages/sheets/src/index.ts | 9 +- .../sheets/src/services/selections/index.ts | 2 +- .../services/selections/selection.service.ts | 8 ++ 17 files changed, 229 insertions(+), 107 deletions(-) diff --git a/packages/core/src/facade/f-usermanager.ts b/packages/core/src/facade/f-usermanager.ts index b77d3ccb86..21afb292fe 100644 --- a/packages/core/src/facade/f-usermanager.ts +++ b/packages/core/src/facade/f-usermanager.ts @@ -29,7 +29,8 @@ export class FUserManager extends FBase { /** * Get current user info - * e.g. `univerAPI.getUserManager().getCurrentUser()` + * @example + * `univerAPI.getUserManager().getCurrentUser()` */ getCurrentUser(): IUser { return this._userManagerService.getCurrentUser(); diff --git a/packages/core/src/services/theme/theme.service.ts b/packages/core/src/services/theme/theme.service.ts index 92da9702e9..14cbe1a6f2 100644 --- a/packages/core/src/services/theme/theme.service.ts +++ b/packages/core/src/services/theme/theme.service.ts @@ -15,11 +15,11 @@ */ import type { Observable } from 'rxjs'; -import { BehaviorSubject } from 'rxjs'; - -import { Disposable, toDisposable } from '../../shared/lifecycle'; import type { Nullable } from '../../shared/types'; +import { BehaviorSubject } from 'rxjs'; +import { Disposable, toDisposable } from '../../shared/lifecycle'; + export interface IStyleSheet { [key: string]: string; } diff --git a/packages/sheets-crosshair-highlight/src/views/widgets/crosshair-highlight.render-controller.ts b/packages/sheets-crosshair-highlight/src/views/widgets/crosshair-highlight.render-controller.ts index e3a4967a11..c17f660379 100644 --- a/packages/sheets-crosshair-highlight/src/views/widgets/crosshair-highlight.render-controller.ts +++ b/packages/sheets-crosshair-highlight/src/views/widgets/crosshair-highlight.render-controller.ts @@ -19,7 +19,7 @@ import type { IRenderContext, IRenderModule, Scene, SpreadsheetSkeleton } from ' import type { ISelectionWithStyle } from '@univerjs/sheets'; import { ColorKit, Disposable, IContextService, Inject, RANGE_TYPE } from '@univerjs/core'; -import { DISABLE_NORMAL_SELECTIONS, IRefSelectionsService, SheetsSelectionsService } from '@univerjs/sheets'; +import { IRefSelectionsService, REF_SELECTIONS_ENABLED, SheetsSelectionsService } from '@univerjs/sheets'; import { getCoordByCell, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import { combineLatest, map, merge, startWith, tap } from 'rxjs'; import { SHEETS_CROSSHAIR_HIGHLIGHT_Z_INDEX } from '../../const'; @@ -71,7 +71,7 @@ export class SheetCrosshairHighlightRenderController extends Disposable implemen const workbook = this._context.unit; this.disposeWithMe(combineLatest([ - this._contextService.subscribeContextValue$(DISABLE_NORMAL_SELECTIONS).pipe(startWith(false)), + this._contextService.subscribeContextValue$(REF_SELECTIONS_ENABLED).pipe(startWith(false)), this._sheetSkeletonManagerService.currentSkeleton$, this._sheetsCrosshairHighlightService.enabled$, this._sheetsCrosshairHighlightService.color$.pipe(tap((color) => (this._color = color))), @@ -90,11 +90,11 @@ export class SheetCrosshairHighlightRenderController extends Disposable implemen this._sheetsSelectionsService.selectionSet$, workbook.activeSheet$.pipe(map(() => this._refSelectionsService.getCurrentSelections())) ), - ]).subscribe(([normalSelDisabled, _, enabled, _color, normalSelections, refSelection]) => { + ]).subscribe(([refSelectionEnabled, _, enabled, _color, normalSelections, refSelection]) => { this._clear(); if (!enabled) return; - const selections = normalSelDisabled ? refSelection : normalSelections; + const selections = refSelectionEnabled ? refSelection : normalSelections; this._rangeCollection.reset(); this._transformSelection(selections, workbook.getActiveSheet()); diff --git a/packages/sheets-formula-ui/src/controllers/prompt.controller.ts b/packages/sheets-formula-ui/src/controllers/prompt.controller.ts index 2dec228bbd..d7cfbdb67c 100644 --- a/packages/sheets-formula-ui/src/controllers/prompt.controller.ts +++ b/packages/sheets-formula-ui/src/controllers/prompt.controller.ts @@ -78,14 +78,11 @@ import { } from '@univerjs/engine-render'; import { convertSelectionDataToRange, - - DISABLE_NORMAL_SELECTIONS, getPrimaryForRange, IRefSelectionsService, + REF_SELECTIONS_ENABLED, SelectionMoveType, - setEndForRange, - SheetsSelectionsService, -} from '@univerjs/sheets'; + setEndForRange, SheetsSelectionsService } from '@univerjs/sheets'; import { IDescriptionService } from '@univerjs/sheets-formula'; import { @@ -429,7 +426,7 @@ export class PromptController extends Disposable { } this._contextService.setContextValue(FOCUSING_EDITOR_INPUT_FORMULA, false); - this._contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, false); + this._contextService.setContextValue(REF_SELECTIONS_ENABLED, false); this._contextService.setContextValue(UNI_DISABLE_CHANGING_FOCUS_KEY, false); this._quitSelectingMode(); @@ -852,10 +849,9 @@ export class PromptController extends Disposable { */ private _contextSwitch() { const config = this._getCurrentBodyDataStreamAndOffset(); - if (config && isFormulaString(config.dataStream)) { this._contextService.setContextValue(FOCUSING_EDITOR_INPUT_FORMULA, true); - this._contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, true); + this._contextService.setContextValue(REF_SELECTIONS_ENABLED, true); this._contextService.setContextValue(UNI_DISABLE_CHANGING_FOCUS_KEY, true); const lastSequenceNodes = @@ -876,9 +872,8 @@ export class PromptController extends Disposable { return; } - this._contextService.setContextValue(FOCUSING_EDITOR_INPUT_FORMULA, false); - this._contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, false); + this._contextService.setContextValue(REF_SELECTIONS_ENABLED, false); this._contextService.setContextValue(UNI_DISABLE_CHANGING_FOCUS_KEY, false); this._formulaPromptService.disableLockedSelectionChange(); diff --git a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts index b4fb61359c..09122ad026 100644 --- a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts +++ b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts @@ -17,7 +17,7 @@ import type { IDisposable, IRangeWithCoord, Nullable, Workbook } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, IRenderContext, IRenderModule, Scene, SpreadsheetSkeleton, Viewport } from '@univerjs/engine-render'; import type { ISelectionStyle, ISelectionWithCoord, ISelectionWithStyle, SheetsSelectionsService, WorkbookSelectionModel } from '@univerjs/sheets'; -import { DisposableCollection, Inject, Injector, RANGE_TYPE, ThemeService, toDisposable } from '@univerjs/core'; +import { DisposableCollection, IContextService, Inject, Injector, RANGE_TYPE, ThemeService, toDisposable } from '@univerjs/core'; import { ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; import { convertSelectionDataToRange, IRefSelectionsService, SelectionMoveType } from '@univerjs/sheets'; import { attachSelectionWithCoord, BaseSelectionRenderService, checkInHeaderRanges, genNormalSelectionStyle, getAllSelection, getCoordByOffset, getSheetObject, SelectionControl, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; @@ -44,13 +44,15 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple @Inject(ThemeService) themeService: ThemeService, @IShortcutService shortcutService: IShortcutService, @Inject(SheetSkeletonManagerService) sheetSkeletonManagerService: SheetSkeletonManagerService, + @IContextService protected readonly _contextService: IContextService, @IRefSelectionsService private readonly _refSelectionsService: SheetsSelectionsService ) { super( injector, themeService, shortcutService, - sheetSkeletonManagerService + sheetSkeletonManagerService, + _contextService ); this._workbookSelections = this._refSelectionsService.getWorkbookSelections(this._context.unitId); @@ -110,6 +112,8 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple const listenerDisposables = new DisposableCollection(); listenerDisposables.add(spreadsheet?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { + if (!this.inRefSelectionMode()) return; + this._onPointerDown(evt, spreadsheet.zIndex + 1, RANGE_TYPE.NORMAL, this._getActiveViewport(evt)); if (evt.button !== 2) { state.stopPropagation(); @@ -118,6 +122,7 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple listenerDisposables.add( spreadsheetRowHeader?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { + if (!this.inRefSelectionMode()) return; const skeleton = this._sheetSkeletonManagerService.getCurrent()!.skeleton; const { row } = getCoordByOffset(evt.offsetX, evt.offsetY, scene, skeleton); const matchSelectionData = checkInHeaderRanges(this._workbookSelections.getCurrentSelections(), row, RANGE_TYPE.ROW); @@ -131,6 +136,7 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple ); listenerDisposables.add(spreadsheetColumnHeader?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { + if (!this.inRefSelectionMode()) return; const skeleton = this._sheetSkeletonManagerService.getCurrent()!.skeleton; const { column } = getCoordByOffset(evt.offsetX, evt.offsetY, scene, skeleton); const matchSelectionData = checkInHeaderRanges(this._workbookSelections.getCurrentSelections(), column, RANGE_TYPE.COLUMN); @@ -146,7 +152,7 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple listenerDisposables.add(spreadsheetLeftTopPlaceholder?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { // remove all other selections this._reset(); - + if (!this.inRefSelectionMode()) return; const skeleton = this._sheetSkeletonManagerService.getCurrent()!.skeleton; const selectionWithStyle = getAllSelection(skeleton); this._addSelectionControlByModelData(selectionWithStyle); diff --git a/packages/sheets-formula-ui/src/views/range-selector/hooks/useRefactorEffect.ts b/packages/sheets-formula-ui/src/views/range-selector/hooks/useRefactorEffect.ts index c032e395d3..509065046f 100644 --- a/packages/sheets-formula-ui/src/views/range-selector/hooks/useRefactorEffect.ts +++ b/packages/sheets-formula-ui/src/views/range-selector/hooks/useRefactorEffect.ts @@ -16,10 +16,10 @@ import { EDITOR_ACTIVATED, IContextService, useDependency } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; -import { DISABLE_NORMAL_SELECTIONS, IRefSelectionsService } from '@univerjs/sheets'; +import { IRefSelectionsService, REF_SELECTIONS_ENABLED } from '@univerjs/sheets'; import { IContextMenuService } from '@univerjs/ui'; -import { useEffect, useLayoutEffect } from 'react'; +import { useEffect, useLayoutEffect } from 'react'; import { RefSelectionsRenderService } from '../../../services/render-services/ref-selections.render-service'; export const useRefactorEffect = (isNeed: boolean, unitId: string) => { @@ -33,12 +33,12 @@ export const useRefactorEffect = (isNeed: boolean, unitId: string) => { useLayoutEffect(() => { if (isNeed) { const d1 = refSelectionsRenderService?.enableSelectionChanging(); - contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, true); + contextService.setContextValue(REF_SELECTIONS_ENABLED, true); contextService.setContextValue(EDITOR_ACTIVATED, true); return () => { contextService.setContextValue(EDITOR_ACTIVATED, false); - contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, false); + contextService.setContextValue(REF_SELECTIONS_ENABLED, false); d1?.dispose(); }; } diff --git a/packages/sheets-ui/src/facade/f-workbook.ts b/packages/sheets-ui/src/facade/f-workbook.ts index 45d9c468bb..e118fde6a3 100644 --- a/packages/sheets-ui/src/facade/f-workbook.ts +++ b/packages/sheets-ui/src/facade/f-workbook.ts @@ -15,10 +15,11 @@ */ import type { IDisposable, Nullable } from '@univerjs/core'; -import type { ICellPosWithEvent, IEditorBridgeServiceVisibleParam, IHoverRichTextInfo, IHoverRichTextPosition, IScrollState } from '@univerjs/sheets-ui'; +import type { RenderManagerService } from '@univerjs/engine-render'; +import type { ICellPosWithEvent, IEditorBridgeServiceVisibleParam, IHoverRichTextInfo, IHoverRichTextPosition, IScrollState, SheetSelectionRenderService } from '@univerjs/sheets-ui'; import { awaitTime, ICommandService, ILogService, toDisposable } from '@univerjs/core'; import { DeviceInputEventType, IRenderManagerService } from '@univerjs/engine-render'; -import { HoverManagerService, SetCellEditVisibleOperation, SheetScrollManagerService } from '@univerjs/sheets-ui'; +import { HoverManagerService, ISheetSelectionRenderService, SetCellEditVisibleOperation, SheetScrollManagerService } from '@univerjs/sheets-ui'; import { FWorkbook } from '@univerjs/sheets/facade'; import { type IDialogPartMethodOptions, IDialogService, type ISidebarMethodOptions, ISidebarService, KeyCode } from '@univerjs/ui'; import { filter } from 'rxjs'; @@ -201,6 +202,70 @@ export class FWorkbookSheetsUIMixin extends FWorkbook implements IFWorkbookSheet const scm = render.with(SheetScrollManagerService); return scm.getScrollStateByParam({ unitId, sheetId }); } + + /** + * Disable selection. After disabled, there would be no response for selection. + * @example + * ``` + * univerAPI.getActiveWorkbook().disableSelection(); + * ``` + */ + disableSelection(): void { + const unitId = this._workbook.getUnitId(); + const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; + const render = renderManagerService.getRenderById(unitId); + if (render) { + (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).disableSelection(); + } + } + + /** + * Enable selection. After this you can select range. + * @example + * ``` + * univerAPI.getActiveWorkbook().enableSelection(); + * ``` + */ + enableSelection(): void { + const unitId = this._workbook.getUnitId(); + const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; + const render = renderManagerService.getRenderById(unitId); + if (render) { + (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).enableSelection(); + } + } + + /** + * Set selection invisible, Unlike disableSelection, selection still works, you just can not see them. + * @example + * ``` + * univerAPI.getActiveWorkbook().transparentSelection(); + * ``` + */ + transparentSelection(): void { + const unitId = this._workbook.getUnitId(); + const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; + const render = renderManagerService.getRenderById(unitId); + if (render) { + (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).transparentSelection(); + } + } + + /** + * Set selection visible. + * @example + * ``` + * univerAPI.getActiveWorkbook().showSelection(); + * ``` + */ + showSelection(): void { + const unitId = this._workbook.getUnitId(); + const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; + const render = renderManagerService.getRenderById(unitId); + if (render) { + (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).showSelection(); + } + } } FWorkbook.extend(FWorkbookSheetsUIMixin); diff --git a/packages/sheets-ui/src/facade/f-worksheet.ts b/packages/sheets-ui/src/facade/f-worksheet.ts index eab7bceaf5..f7dc6d0d6f 100644 --- a/packages/sheets-ui/src/facade/f-worksheet.ts +++ b/packages/sheets-ui/src/facade/f-worksheet.ts @@ -16,10 +16,10 @@ import type { IDisposable, IRange, Nullable } from '@univerjs/core'; import type { RenderManagerService } from '@univerjs/engine-render'; -import type { IScrollState, IViewportScrollState, SheetSelectionRenderService } from '@univerjs/sheets-ui'; +import type { IScrollState, IViewportScrollState } from '@univerjs/sheets-ui'; import { ICommandService, toDisposable } from '@univerjs/core'; import { IRenderManagerService, SHEET_VIEWPORT_KEY, sheetContentViewportKeys } from '@univerjs/engine-render'; -import { ChangeZoomRatioCommand, ISheetSelectionRenderService, SheetScrollManagerService, SheetSkeletonManagerService, SheetsScrollRenderController } from '@univerjs/sheets-ui'; +import { ChangeZoomRatioCommand, SheetScrollManagerService, SheetSkeletonManagerService, SheetsScrollRenderController } from '@univerjs/sheets-ui'; import { FWorksheet } from '@univerjs/sheets/facade'; export interface IFWorksheetSkeletonMixin { @@ -175,30 +175,6 @@ export class FWorksheetSkeletonMixin extends FWorksheet implements IFWorksheetSk } return toDisposable(() => {}); } - - /** - * Hide selection box. - */ - disableSelection(): void { - const unitId = this._workbook.getUnitId(); - const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; - const render = renderManagerService.getRenderById(unitId); - if (render) { - (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).disableSelection(); - } - } - - /** - * Show selection box. - */ - enableSelection(): void { - const unitId = this._workbook.getUnitId(); - const renderManagerService = this._injector.get(IRenderManagerService) as RenderManagerService; - const render = renderManagerService.getRenderById(unitId); - if (render) { - (render.with(ISheetSelectionRenderService) as SheetSelectionRenderService).enableSelection(); - } - } } FWorksheet.extend(FWorksheetSkeletonMixin); diff --git a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts index 1d78b0f54c..dd01940273 100644 --- a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts @@ -17,23 +17,24 @@ import type { ICellInfo, ICellWithCoord, + IContextService, IDisposable, IFreeze, IInterceptor, Injector, IRange, IRangeWithCoord, - Nullable, - ThemeService, -} from '@univerjs/core'; + IStyleSheet, + Nullable } from '@univerjs/core'; import type { IMouseEvent, IPointerEvent, IRenderModule, Scene, SpreadsheetSkeleton, Viewport } from '@univerjs/engine-render'; -import type { ISelectionStyle, ISelectionWithCoord, ISelectionWithStyle } from '@univerjs/sheets'; import type { IShortcutService } from '@univerjs/ui'; import type { Observable, Subscription } from 'rxjs'; import type { SheetSkeletonManagerService } from '../sheet-skeleton-manager.service'; -import { convertCellToRange, createIdentifier, Disposable, InterceptorManager, RANGE_TYPE } from '@univerjs/core'; - +import { + convertCellToRange, createIdentifier, Disposable, InterceptorManager, RANGE_TYPE, ThemeService } from '@univerjs/core'; import { ScrollTimer, ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; + +import { type ISelectionStyle, type ISelectionWithCoord, type ISelectionWithStyle, REF_SELECTIONS_ENABLED, SELECTIONS_ENABLED } from '@univerjs/sheets'; import { BehaviorSubject, Subject } from 'rxjs'; import { SHEET_COMPONENT_SELECTION_LAYER_INDEX } from '../../common/keys'; import { genNormalSelectionStyle, RANGE_FILL_PERMISSION_CHECK, RANGE_MOVE_PERMISSION_CHECK } from './const'; @@ -173,6 +174,7 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele readonly selectionMoveStart$ = this._selectionMoveStart$.asObservable(); private _selectionMoving = false; + protected _selectionTheme: ThemeService; get selectionMoving(): boolean { return this._selectionMoving; } @@ -188,10 +190,13 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele protected readonly _themeService: ThemeService, // WTF: why shortcutService is injected here? protected readonly _shortcutService: IShortcutService, - protected readonly _sheetSkeletonManagerService: SheetSkeletonManagerService + protected readonly _sheetSkeletonManagerService: SheetSkeletonManagerService, + protected readonly contextService: IContextService + ) { super(); - this._resetSelectionStyle(); + // this._resetSelectionStyle(); + this._initSelectionThemeFromThemeService(); this._initMoving(); } @@ -219,9 +224,9 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele /** * Reset this._selectionStyle to default normal selection style */ - protected _resetSelectionStyle(): void { - this._setSelectionStyle(genNormalSelectionStyle(this._themeService)); - } + // protected _resetSelectionStyle(): void { + // this._setSelectionStyle(genNormalSelectionStyle(this._themeService)); + // } /** @deprecated This should not be provided by the selection render service. */ getViewPort(): Viewport { @@ -235,7 +240,7 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele newSelectionControl(scene: Scene, skeleton: SpreadsheetSkeleton, selection: ISelectionWithStyle): SelectionControl { const zIndex = this.getSelectionControls().length; const { rowHeaderWidth, columnHeaderHeight } = skeleton; - const control = new SelectionControl(scene, zIndex, this._themeService, { + const control = new SelectionControl(scene, zIndex, this._selectionTheme, { highlightHeader: this._highlightHeader, rowHeaderWidth, columnHeaderHeight, @@ -247,7 +252,7 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele control.setControlExtension({ skeleton, scene, - themeService: this._themeService, + themeService: this._selectionTheme, injector: this._injector, selectionHooks: { selectionMoveEnd: (): void => { @@ -275,10 +280,13 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele const selectionWithStyle = selectionsWithStyleList[i]; const selectionWithCoord = attachSelectionWithCoord(selectionWithStyle, this._skeleton); const control = allSelectionControls[i]; + if (control) { control.updateRangeBySelectionWithCoord(selectionWithCoord); } else { - this.newSelectionControl(this._scene!, skeleton, selectionWithStyle); + if (this.isSelectionEnabled()) { + this.newSelectionControl(this._scene!, skeleton, selectionWithStyle); + } } } if (selectionsWithStyleList.length < allSelectionControls.length) { @@ -295,6 +303,16 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele this._selectionMoveEnd$.next(this.getSelectionDataWithStyle()); } + _initSelectionThemeFromThemeService() { + const currTheme = this._themeService.getCurrentTheme(); + this._selectionTheme = new ThemeService(); + this._selectionTheme.setTheme(currTheme); + } + + setSelectionTheme(prop: IStyleSheet) { + this._selectionTheme.setTheme(prop); + } + protected _changeRuntime(skeleton: SpreadsheetSkeleton, scene: Scene, viewport?: Viewport): void { this._skeleton = skeleton; this._scene = scene; @@ -337,7 +355,7 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele */ protected _addSelectionControlByModelData(selectionWithStyle: ISelectionWithStyle): SelectionControl { const skeleton = this._skeleton; - const style = selectionWithStyle.style ?? genNormalSelectionStyle(this._themeService); + const style = selectionWithStyle.style ?? genNormalSelectionStyle(this._selectionTheme); const scene = this._scene; selectionWithStyle.style = style; @@ -893,6 +911,18 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele // activeControl.updateRange(newSelectionRange, currentCell); } + + isSelectionEnabled(): boolean { + return this.contextService.getContextValue(SELECTIONS_ENABLED); + } + + isSelectionDisabled(): boolean { + return this.contextService.getContextValue(SELECTIONS_ENABLED) === false; + } + + inRefSelectionMode(): boolean { + return this.contextService.getContextValue(REF_SELECTIONS_ENABLED); + } } export function selectionDataForSelectAll(skeleton: SpreadsheetSkeleton): ISelectionWithStyle { diff --git a/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts b/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts index 6238681bdd..32e6d4432b 100644 --- a/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/mobile-selection-render.service.ts @@ -39,7 +39,7 @@ import { toDisposable, } from '@univerjs/core'; import { ScrollTimer, ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; -import { convertSelectionDataToRange, DISABLE_NORMAL_SELECTIONS, SelectionMoveType, SetSelectionsOperation, SheetsSelectionsService } from '@univerjs/sheets'; +import { convertSelectionDataToRange, REF_SELECTIONS_ENABLED, SelectionMoveType, SetSelectionsOperation, SheetsSelectionsService } from '@univerjs/sheets'; import { IShortcutService } from '@univerjs/ui'; import { distinctUntilChanged, startWith } from 'rxjs'; import { getCoordByOffset, getSheetObject } from '../../controllers/utils/component-tools'; @@ -77,14 +77,16 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi @Inject(SheetSkeletonManagerService) sheetSkeletonManagerService: SheetSkeletonManagerService, @ILogService private readonly _logService: ILogService, @ICommandService private readonly _commandService: ICommandService, - @IContextService private readonly _contextService: IContextService, + @IContextService protected readonly _contextService: IContextService, @Inject(SheetScrollManagerService) private readonly _scrollManagerService: SheetScrollManagerService + ) { super( injector, themeService, shortcutService, - sheetSkeletonManagerService + sheetSkeletonManagerService, + _contextService ); this._workbookSelections = selectionManagerService.getWorkbookSelections(this._context.unitId); this._init(); @@ -251,7 +253,7 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi this.disposeWithMe(this.selectionMoveStart$.subscribe((params) => this._updateSelections(params, SelectionMoveType.MOVE_START))); this.disposeWithMe(this.selectionMoving$.subscribe((params) => this._updateSelections(params, SelectionMoveType.MOVING))); - this.disposeWithMe(this._contextService.subscribeContextValue$(DISABLE_NORMAL_SELECTIONS) + this.disposeWithMe(this._contextService.subscribeContextValue$(REF_SELECTIONS_ENABLED) .pipe(startWith(false), distinctUntilChanged()) .subscribe((disabled) => { if (disabled) { @@ -463,7 +465,7 @@ export class MobileSheetsSelectionRenderService extends BaseSelectionRenderServi // same as PC private _normalSelectionDisabled(): boolean { - return this._contextService.getContextValue(DISABLE_NORMAL_SELECTIONS); + return this._contextService.getContextValue(REF_SELECTIONS_ENABLED); } override getSelectionControls() { diff --git a/packages/sheets-ui/src/services/selection/selection-render.service.ts b/packages/sheets-ui/src/services/selection/selection-render.service.ts index fbae8f4bb0..f130ebbc19 100644 --- a/packages/sheets-ui/src/services/selection/selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/selection-render.service.ts @@ -21,14 +21,15 @@ import type { ISheetObjectParam } from '../../controllers/utils/component-tools' import type { SelectionControl } from './selection-control'; import { ICommandService, IContextService, ILogService, Inject, Injector, RANGE_TYPE, ThemeService, toDisposable } from '@univerjs/core'; import { ScrollTimerType, SHEET_VIEWPORT_KEY, Vector2 } from '@univerjs/engine-render'; -import { convertSelectionDataToRange, DISABLE_NORMAL_SELECTIONS, SelectionMoveType, SetSelectionsOperation, SheetsSelectionsService } from '@univerjs/sheets'; +import { convertSelectionDataToRange, REF_SELECTIONS_ENABLED, SelectionMoveType, SELECTIONS_ENABLED, SetSelectionsOperation, SheetsSelectionsService } from '@univerjs/sheets'; import { IShortcutService } from '@univerjs/ui'; import { distinctUntilChanged, merge, startWith } from 'rxjs'; import { getCoordByOffset, getSheetObject } from '../../controllers/utils/component-tools'; + import { isThisColSelected, isThisRowSelected } from '../../controllers/utils/selections-tools'; import { SheetSkeletonManagerService } from '../sheet-skeleton-manager.service'; - import { BaseSelectionRenderService, getTopLeftSelectionOfCurrSheet, selectionDataForSelectAll } from './base-selection-render.service'; +import { genNormalSelectionStyle } from './const'; import { attachSelectionWithCoord } from './util'; /** @@ -49,13 +50,14 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl @Inject(SheetSkeletonManagerService) sheetSkeletonManagerService: SheetSkeletonManagerService, @ILogService private readonly _logService: ILogService, @ICommandService private readonly _commandService: ICommandService, - @IContextService private readonly _contextService: IContextService + @IContextService protected readonly _contextService: IContextService ) { super( injector, themeService, shortcutService, - sheetSkeletonManagerService + sheetSkeletonManagerService, + _contextService ); this._workbookSelections = selectionManagerService.getWorkbookSelections(this._context.unitId); @@ -64,7 +66,7 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl private _init(): void { const sheetObject = this._getSheetObject(); - + this._contextService.setContextValue(SELECTIONS_ENABLED, true); this._initEventListeners(sheetObject); this._initSelectionModelChangeListener(); this._initThemeChangeListener(); @@ -77,7 +79,8 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl const { scene } = this._context; this.disposeWithMe(spreadsheet?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { - if (this._normalSelectionDisabled()) return; + if (this.isSelectionDisabled()) return; + if (this.inRefSelectionMode()) return; this._onPointerDown(evt, spreadsheet.zIndex + 1, RANGE_TYPE.NORMAL, this._getActiveViewport(evt)); if (evt.button !== 2) { state.stopPropagation(); @@ -86,7 +89,8 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl this.disposeWithMe( spreadsheetRowHeader?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { - if (this._normalSelectionDisabled()) return; + if (this.isSelectionDisabled()) return; + if (this.inRefSelectionMode()) return; const skeleton = this._sheetSkeletonManagerService.getCurrent()!.skeleton; const { row } = getCoordByOffset(evt.offsetX, evt.offsetY, scene, skeleton); @@ -101,7 +105,8 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl ); this.disposeWithMe(spreadsheetColumnHeader?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { - if (this._normalSelectionDisabled()) return; + if (this.isSelectionDisabled()) return; + if (this.inRefSelectionMode()) return; const skeleton = this._sheetSkeletonManagerService.getCurrent()!.skeleton; const { column } = getCoordByOffset(evt.offsetX, evt.offsetY, scene, skeleton); @@ -116,7 +121,8 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl })); this.disposeWithMe(spreadsheetLeftTopPlaceholder?.onPointerDown$.subscribeEvent((evt: IPointerEvent | IMouseEvent, state) => { - if (this._normalSelectionDisabled()) return; + if (this.isSelectionDisabled()) return; + if (this.inRefSelectionMode()) return; this._reset(); // remove all other selections @@ -133,17 +139,13 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl private _initThemeChangeListener(): void { this.disposeWithMe(this._themeService.currentTheme$.subscribe(() => { - this._resetSelectionStyle(); + this._initSelectionThemeFromThemeService(); const selections = this._workbookSelections.getCurrentSelections(); if (!selections) return; this.resetSelectionsByModelData(selections); })); } - private _normalSelectionDisabled(): boolean { - return this._contextService.getContextValue(DISABLE_NORMAL_SELECTIONS); - } - /** * Response for selection model changing. */ @@ -157,11 +159,36 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl } disableSelection() { - this._contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, true); + this._contextService.setContextValue(SELECTIONS_ENABLED, false); } enableSelection() { - this._contextService.setContextValue(DISABLE_NORMAL_SELECTIONS, false); + this._contextService.setContextValue(SELECTIONS_ENABLED, true); + } + + transparentSelection() { + this.setSelectionTheme({ + primaryColor: 'transparent', + }); + const selectionsWithStyle = this._workbookSelections.getCurrentSelections(); + for (let index = 0; index < selectionsWithStyle.length; index++) { + const selectionWithStyle = selectionsWithStyle[index]; + selectionWithStyle.style = genNormalSelectionStyle(this._selectionTheme); + } + this.resetSelectionsByModelData(selectionsWithStyle); + } + + showSelection() { + const currTheme = this._themeService.getCurrentTheme(); + this.setSelectionTheme(currTheme); + const selectionsWithStyle = this._workbookSelections.getCurrentSelections(); + for (let index = 0; index < selectionsWithStyle.length; index++) { + const selectionWithStyle = selectionsWithStyle[index]; + if (selectionWithStyle.style) { + selectionWithStyle.style = genNormalSelectionStyle(this._selectionTheme); + } + } + this.resetSelectionsByModelData(selectionsWithStyle); } /** @@ -171,10 +198,27 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl this.disposeWithMe(this.selectionMoveStart$.subscribe((params) => this._updateSelections(params, SelectionMoveType.MOVE_START))); this.disposeWithMe(this.selectionMoving$.subscribe((params) => this._updateSelections(params, SelectionMoveType.MOVING))); - this.disposeWithMe(this._contextService.subscribeContextValue$(DISABLE_NORMAL_SELECTIONS) + this.disposeWithMe(this._contextService.subscribeContextValue$(REF_SELECTIONS_ENABLED) .pipe(startWith(false), distinctUntilChanged()) - .subscribe((disabled) => { - if (disabled) { + .subscribe((enabled) => { + if (enabled) { + this._renderDisposable?.dispose(); + this._renderDisposable = null; + this._reset(); + } else { + this._renderDisposable = toDisposable( + //TODO @lumixraku ! these would only show the last selection, not all + this.selectionMoveEnd$.subscribe((params) => { + this._updateSelections(params, SelectionMoveType.MOVE_END); + }) + ); + } + })); + + this.disposeWithMe(this._contextService.subscribeContextValue$(SELECTIONS_ENABLED) + .pipe(startWith(true), distinctUntilChanged()) + .subscribe((enabled) => { + if (!enabled) { this._renderDisposable?.dispose(); this._renderDisposable = null; this._reset(); @@ -231,8 +275,6 @@ export class SheetSelectionRenderService extends BaseSelectionRenderService impl const prevSheetId = this._skeleton?.worksheet?.getSheetId(); this._changeRuntime(skeleton, scene, viewportMain); - if (this._normalSelectionDisabled()) return; - if (prevSheetId !== skeleton.worksheet.getSheetId()) { // If there is no initial selection, add one by default in the top left corner. const selections = this._workbookSelections.getCurrentSelections(); diff --git a/packages/sheets/src/commands/utils/selection-command-util.ts b/packages/sheets/src/commands/utils/selection-command-util.ts index 78cac12a21..f8f6b4a374 100644 --- a/packages/sheets/src/commands/utils/selection-command-util.ts +++ b/packages/sheets/src/commands/utils/selection-command-util.ts @@ -17,13 +17,13 @@ import type { IAccessor } from '@univerjs/core'; import { IContextService } from '@univerjs/core'; import { IRefSelectionsService } from '../../services/selections/ref-selections.service'; -import { DISABLE_NORMAL_SELECTIONS, SheetsSelectionsService } from '../../services/selections/selection.service'; +import { REF_SELECTIONS_ENABLED, SheetsSelectionsService } from '../../services/selections/selection.service'; export function getSelectionsService( accessor: IAccessor ): SheetsSelectionsService { const contextService = accessor.get(IContextService); - const disabledNormalSelections = contextService.getContextValue(DISABLE_NORMAL_SELECTIONS); + const isInRefSelectionMode = contextService.getContextValue(REF_SELECTIONS_ENABLED); - return accessor.get(disabledNormalSelections ? IRefSelectionsService : SheetsSelectionsService); + return accessor.get(isInRefSelectionMode ? IRefSelectionsService : SheetsSelectionsService); } diff --git a/packages/sheets/src/facade/f-range.ts b/packages/sheets/src/facade/f-range.ts index 4c145625ca..be3b1e96da 100644 --- a/packages/sheets/src/facade/f-range.ts +++ b/packages/sheets/src/facade/f-range.ts @@ -225,7 +225,10 @@ export class FRange extends FBase { // #region editing /** * Set background color for current range. - * e.g. `univerAPI.getActiveWorkbook().getActiveSheet().getActiveRange().setBackgroundColor('red') + * @example + * ``` + * univerAPI.getActiveWorkbook().getActiveSheet().getActiveRange().setBackgroundColor('red') + * ``` * @param color {string} */ setBackgroundColor(color: string): Promise { diff --git a/packages/sheets/src/facade/f-worksheet.ts b/packages/sheets/src/facade/f-worksheet.ts index 98d16fb3a9..e89452df2f 100644 --- a/packages/sheets/src/facade/f-worksheet.ts +++ b/packages/sheets/src/facade/f-worksheet.ts @@ -1064,6 +1064,7 @@ export class FWorksheet extends FBase { * To unfreeze all columns, set this value to 0. */ setFrozenColumns(columns: number): void; + /** * Set freeze column, then the range from startColumn to endColumn will be fixed. * e.g. setFrozenColumns(0, 2) will fix the column range from 0 to 2. diff --git a/packages/sheets/src/index.ts b/packages/sheets/src/index.ts index 9db861e12e..51bf6e3303 100644 --- a/packages/sheets/src/index.ts +++ b/packages/sheets/src/index.ts @@ -48,14 +48,7 @@ export { BorderStyleManagerService, type IBorderInfo } from './services/border-s export * from './services/permission/permission-point'; export { WorksheetPermissionService } from './services/permission/worksheet-permission/worksheet-permission.service'; export { WorkbookPermissionService } from './services/permission/workbook-permission/workbook-permission.service'; -export { - DISABLE_NORMAL_SELECTIONS, - IRefSelectionsService, - RefSelectionsService, - SelectionMoveType, - SheetsSelectionsService, - WorkbookSelectionModel, -} from './services/selections'; +export * from './services/selections'; export { getAddMergeMutationRangeByType } from './controllers/merge-cell.controller'; export { NumfmtService } from './services/numfmt/numfmt.service'; export type { INumfmtItem, INumfmtItemWithCache } from './services/numfmt/type'; diff --git a/packages/sheets/src/services/selections/index.ts b/packages/sheets/src/services/selections/index.ts index f86908b51d..aa0ba9b18c 100644 --- a/packages/sheets/src/services/selections/index.ts +++ b/packages/sheets/src/services/selections/index.ts @@ -16,5 +16,5 @@ export { IRefSelectionsService, RefSelectionsService } from './ref-selections.service'; export { WorkbookSelectionModel } from './selection-data-model'; -export { DISABLE_NORMAL_SELECTIONS, SheetsSelectionsService } from './selection.service'; +export { DISABLE_NORMAL_SELECTIONS, REF_SELECTIONS_ENABLED, SELECTIONS_ENABLED, SheetsSelectionsService } from './selection.service'; export { type ISelectionManagerSearchParam, SelectionMoveType } from './type'; diff --git a/packages/sheets/src/services/selections/selection.service.ts b/packages/sheets/src/services/selections/selection.service.ts index 1ba4920279..e1944a0646 100644 --- a/packages/sheets/src/services/selections/selection.service.ts +++ b/packages/sheets/src/services/selections/selection.service.ts @@ -217,4 +217,12 @@ export class SheetsSelectionsService extends RxDisposable { } /** An context key to disable normal selections if its value is set to `true`. */ +// so Bad! why not enableXXX export const DISABLE_NORMAL_SELECTIONS = 'DISABLE_NORMAL_SELECTIONS'; +export const SELECTIONS_ENABLED = 'SELECTIONS_ENABLED'; +export const REF_SELECTIONS_ENABLED = 'REF_SELECTIONS_ENABLED'; +export const SELECTION_MODE = '__SELECTION_MODE__'; +export enum SelectionMode { + NORMAL, + REF, +}