From 10a89be0b184df2750a4b3eceb48db205cb83e95 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 5 Nov 2024 10:22:31 -0500 Subject: fixed display of where control point will be added on mouse moves. fixed clickable ink line to not select fill area unless its actually painted. added end cap properties to ink stroke ui. enabled more than one ink stroke to show editable control points when multiselected. --- src/client/views/InkingStroke.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/client/views/InkingStroke.tsx') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 5199eb02b..f847db6c2 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -21,7 +21,7 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ import { Property } from 'csstype'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DashColor, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; @@ -66,9 +66,14 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() private _handledClick = false; // flag denoting whether ink stroke has handled a psuedo-click onPointerUp so that the real onClick event can be stopPropagated private _disposers: { [key: string]: IReactionDisposer } = {}; + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + @observable _nearestSeg?: number = undefined; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) @observable _nearestT?: number = undefined; // nearest t value within the nearest Bezier segment " - @observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke "" + @observable _nearestScrPt?: { X: number; Y: number } = { X: 0, Y: 0 }; // nearst screen point on the ink stroke "" componentDidMount() { this._props.setContentViewBox?.(this); @@ -155,6 +160,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; const isEditing = InkStrokeProperties.Instance._controlButton && this._props.isSelected(); this.controlUndo = undefined; + this._nearestScrPt = undefined; setupMoveUpEvents( this, e, @@ -275,7 +281,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() .map(p => ({ X: p[0], Y: p[1] })); const { distance, nearestT, nearestSeg, nearestPt } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); - if (distance < 40) { + if (distance < 40 && !e.buttons) { this._nearestT = nearestT; this._nearestSeg = nearestSeg; this._nearestScrPt = nearestPt; @@ -427,7 +433,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() StrCast(this.layoutDoc.stroke_lineJoin) as Property.StrokeLinejoin, StrCast(this.layoutDoc.stroke_lineCap) as Property.StrokeLinecap, StrCast(this.layoutDoc.stroke_bezier), - !closed || !fillColor || DashColor(fillColor).alpha() === 0 ? 'none' : fillColor, + 'none', startMarker, endMarker, markerScale, -- cgit v1.2.3-70-g09d2 From 6201fb8595729d049885d91278e990e49588f6f5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Nov 2024 12:47:15 -0500 Subject: fixed clicking on filled closed strokes to select them.. fixed equationBox initial width. fixed line mode for ink to always create lines. fixed contextMenu to reset selectedIndex after being hidden. added reveal options for comparisonbox to contexst menu. --- src/client/views/ContextMenu.tsx | 1 + src/client/views/GestureOverlay.tsx | 2 +- src/client/views/InkingStroke.tsx | 4 ++-- src/client/views/nodes/ComparisonBox.tsx | 39 ++++++++++++++++++++++++-------- src/client/views/nodes/EquationBox.scss | 4 +++- src/client/views/nodes/EquationBox.tsx | 1 - 6 files changed, 36 insertions(+), 15 deletions(-) (limited to 'src/client/views/InkingStroke.tsx') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 1931d7c2a..eae45221c 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -142,6 +142,7 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } this.clearItems(); this._display = false; this._shouldDisplay = false; + this._selectedIndex = -1; return wasOpen; }; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 2d6cd03e0..b0a750a9a 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -256,7 +256,7 @@ export class GestureOverlay extends ObservableReactComponent { switch (name) { case Gestures.Line: - if (cuspArray.length > 2) return undefined; + if (cuspArray.length > 2 && Score < 1) return undefined; // eslint-disable-next-line no-fallthrough case Gestures.Triangle: case Gestures.Rectangle: diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index f847db6c2..f555808ef 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -315,7 +315,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() componentUI = (boundsLeft: number, boundsTop: number): null | JSX.Element => { const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); - const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.ScreenToLocalBoxXf().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke + const screenSpaceCenterlineStrokeWidth = 3; //Math.min(3, inkStrokeWidth * this.ScreenToLocalBoxXf().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke const screenInkWidth = this.ScreenToLocalBoxXf().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); @@ -433,7 +433,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() StrCast(this.layoutDoc.stroke_lineJoin) as Property.StrokeLinejoin, StrCast(this.layoutDoc.stroke_lineCap) as Property.StrokeLinecap, StrCast(this.layoutDoc.stroke_bezier), - 'none', + closed && fillColor && DashColor(fillColor).alpha() ? fillColor : 'none', startMarker, endMarker, markerScale, diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 672c189ba..e0c360132 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import axios from 'axios'; -import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; @@ -30,6 +30,7 @@ import './ComparisonBox.scss'; import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; +import { TraceMobx } from '../../../fields/util'; const API_URL = 'https://api.unsplash.com/search/photos'; @@ -143,19 +144,28 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() this._reactDisposer.select = reaction( () => this._props.isSelected(), selected => { - if (selected && this.revealOp !== flashcardRevealOp.SLIDE) this.activateContent(); - !selected && (this._childActive = false); + if (selected) { + switch (this.revealOp) { + default: + case flashcardRevealOp.FLIP: this.activateContent(); break; + case flashcardRevealOp.SLIDE: break; + } // prettier-ignore + } else { + this._childActive = false; + } }, // what it should update to { fireImmediately: true } ); - this._reactDisposer.hover = reaction( - () => this._props.isContentActive(), - hover => { - if (!hover) { - this.revealOp === flashcardRevealOp.FLIP && this.animateFlipping(this.frontKey); - this.revealOp === flashcardRevealOp.SLIDE && this.animateSliding(this._props.PanelWidth() - 3); + this._reactDisposer.inactive = reaction( + () => !this._props.isContentActive(), + inactive => { + if (inactive) { + switch (this.revealOp) { + case flashcardRevealOp.FLIP: this.animateFlipping(this.frontKey); break; + case flashcardRevealOp.SLIDE: this.animateSliding(this._props.PanelWidth() - 3); break; + } // prettier-ignore } - }, // what it should update to + }, { fireImmediately: true } ); } @@ -197,7 +207,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() @computed get clipWidth() { return NumCast(this.layoutDoc[this.clipWidthKey], this.isFlashcard ? 100: 50); } // prettier-ignore @computed get clipHeight() { return NumCast(this.layoutDoc[this.clipHeightKey], 200); } // prettier-ignore @computed get revealOp() { return StrCast(this.layoutDoc[this.revealOpKey], StrCast(this.containerDoc?.revealOp, this.isFlashcard ? flashcardRevealOp.FLIP : flashcardRevealOp.SLIDE)) as flashcardRevealOp; } // prettier-ignore + set revealOp(op:flashcardRevealOp) { this.layoutDoc[this.revealOpKey] = op; } // prettier-ignore @computed get revealOpHover() { return BoolCast(this.layoutDoc[this.revealOpKey+"_hover"], BoolCast(this.containerDoc?.revealOp_hover)); } // prettier-ignore + set revealOpHover(on:boolean) { this.layoutDoc[this.revealOpKey+"_hover"] = on; } // prettier-ignore @computed get loading() { return this._loading; } // prettier-ignore set loading(value) { runInAction(() => { this._loading = value; })} // prettier-ignore @@ -616,6 +628,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() const appearance = ContextMenu.Instance.findByDescription('Appearance...'); const appearanceItems = appearance?.subitems ?? []; appearanceItems.push({ description: 'Create ChatCard', event: () => this.askGPT(GPTCallType.CHATCARD), icon: 'id-card' }); + appearanceItems.push({ + description: 'Reveal by ' + (this.revealOp === flashcardRevealOp.FLIP ? 'Sliding' : 'Flipping'), + event: () => (this.revealOp = this.revealOp === flashcardRevealOp.FLIP ? flashcardRevealOp.SLIDE : flashcardRevealOp.FLIP), + icon: 'id-card', + }); + appearanceItems.push({ description: (this.revealOpHover ? 'Click ' : 'Hover ') + ' to reveal', event: () => (this.revealOpHover = !this.revealOpHover), icon: 'id-card' }); !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); }; @@ -792,6 +810,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() ); render() { + TraceMobx(); const renderMode = new Map JSX.Element>([ [flashcardRevealOp.FLIP, this.renderAsFlip], [flashcardRevealOp.SLIDE, this.renderAsBeforeAfter]]); // prettier-ignore diff --git a/src/client/views/nodes/EquationBox.scss b/src/client/views/nodes/EquationBox.scss index 5009ec7a7..cbd13d924 100644 --- a/src/client/views/nodes/EquationBox.scss +++ b/src/client/views/nodes/EquationBox.scss @@ -3,7 +3,9 @@ .equationBox-cont { transform-origin: center; background-color: #e7e7e7; + width: fit-content; + min-width: 100%; > span { - width: 100%; + width: fit-content; } } diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 290c90d6e..472fa56a0 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -119,7 +119,6 @@ export class EquationBox extends ViewBoxBaseComponent() { onPointerDown={e => !e.ctrlKey && e.stopPropagation()} style={{ transform: `scale(${scale})`, - width: 'fit-content', // `${100 / scale}%`, height: `${100 / scale}%`, pointerEvents: !this._props.isSelected() ? 'none' : undefined, fontSize: StrCast(this.Document._text_fontSize), -- cgit v1.2.3-70-g09d2