Skip to content

Commit

Permalink
Merge pull request #191 from cocopon/drag-to-tweak
Browse files Browse the repository at this point in the history
Adding tweaking knob to numeric inputs
  • Loading branch information
cocopon authored Mar 11, 2021
2 parents 6a06845 + 811da69 commit 151f230
Show file tree
Hide file tree
Showing 40 changed files with 830 additions and 405 deletions.
1 change: 1 addition & 0 deletions lib/api/input-binding-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function createApi(target: BindingTarget) {
const value = new Value(0);
const ic = new NumberTextController(doc, {
baseStep: 1,
draggingScale: 1,
formatter: createNumberFormatter(0),
parser: parseNumber,
value: value,
Expand Down
4 changes: 2 additions & 2 deletions lib/pane/input-number-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {Constraint} from '../plugin/common/constraint/constraint';
import {StepConstraint} from '../plugin/common/constraint/step';
import {Value} from '../plugin/common/model/value';
import {ListController} from '../plugin/input-bindings/common/controller/list';
import {TextController} from '../plugin/input-bindings/common/controller/text';
import {NumberTextController} from '../plugin/input-bindings/number/controller/number-text';
import {SliderTextController} from '../plugin/input-bindings/number/controller/slider-text';

function createPane(): Tweakpane {
Expand All @@ -21,7 +21,7 @@ function createPane(): Tweakpane {
describe(Tweakpane.name, () => {
[
{
expectedClass: TextController,
expectedClass: NumberTextController,
params: {},
value: 3.14,
},
Expand Down
34 changes: 29 additions & 5 deletions lib/plugin/common/model/value-sync.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Value} from './value';

/**
* @hidden
* Synchronizes two values.
*/
export function connect<T1, T2>({
export function connectValues<T1, T2>({
primary,
secondary,
forward,
Expand All @@ -14,11 +14,35 @@ export function connect<T1, T2>({
forward: (primary: Value<T1>, secondary: Value<T2>) => T2;
backward: (primary: Value<T1>, secondary: Value<T2>) => T1;
}) {
// Prevents an event firing loop
// e.g.
// primary changed
// -> applies changes to secondary
// -> secondary changed
// -> applies changes to primary
// -> ...
let changing = false;
function preventFeedback(callback: () => void) {
if (changing) {
return;
}
changing = true;
callback();
changing = false;
}

primary.emitter.on('change', () => {
secondary.rawValue = forward(primary, secondary);
preventFeedback(() => {
secondary.rawValue = forward(primary, secondary);
});
});
secondary.emitter.on('change', () => {
primary.rawValue = backward(primary, secondary);
preventFeedback(() => {
primary.rawValue = backward(primary, secondary);
});
});

preventFeedback(() => {
secondary.rawValue = forward(primary, secondary);
});
secondary.rawValue = forward(primary, secondary);
}
84 changes: 61 additions & 23 deletions lib/plugin/common/view/pointer-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,31 @@ export interface PointerData {
width: number;
};
/**
* The X coordinate in the element.
* The pointer coordinates.
*/
x: number;
/**
* The Y coordinate in the element.
*/
y: number;
point: {
/**
* The X coordinate in the element.
*/
x: number;
/**
* The Y coordinate in the element.
*/
y: number;
} | null;
}

function computeOffset(ev: MouseEvent, elem: HTMLElement): [number, number] {
function computeOffset(
ev: MouseEvent,
elem: HTMLElement,
): {x: number; y: number} {
// NOTE: OffsetX/Y should be computed from page and window properties to capture mouse events
const win = elem.ownerDocument.defaultView;
const rect = elem.getBoundingClientRect();
return [
ev.pageX - (((win && win.scrollX) || 0) + rect.left),
ev.pageY - (((win && win.scrollY) || 0) + rect.top),
];
return {
x: ev.pageX - (((win && win.scrollX) || 0) + rect.left),
y: ev.pageY - (((win && win.scrollY) || 0) + rect.top),
};
}

/**
Expand Down Expand Up @@ -58,6 +66,7 @@ export class PointerHandler {
this.onDocumentMouseMove_ = this.onDocumentMouseMove_.bind(this);
this.onDocumentMouseUp_ = this.onDocumentMouseUp_.bind(this);
this.onMouseDown_ = this.onMouseDown_.bind(this);
this.onTouchEnd_ = this.onTouchEnd_.bind(this);
this.onTouchMove_ = this.onTouchMove_.bind(this);
this.onTouchStart_ = this.onTouchStart_.bind(this);

Expand All @@ -69,22 +78,27 @@ export class PointerHandler {
if (supportsTouch(doc)) {
element.addEventListener('touchstart', this.onTouchStart_);
element.addEventListener('touchmove', this.onTouchMove_);
element.addEventListener('touchend', this.onTouchEnd_);
} else {
element.addEventListener('mousedown', this.onMouseDown_);
doc.addEventListener('mousemove', this.onDocumentMouseMove_);
doc.addEventListener('mouseup', this.onDocumentMouseUp_);
}
}

private computePosition_(offsetX: number, offsetY: number): PointerData {
private computePosition_(offset?: {x: number; y: number}): PointerData {
const rect = this.element.getBoundingClientRect();
return {
bounds: {
width: rect.width,
height: rect.height,
},
x: offsetX,
y: offsetY,
point: offset
? {
x: offset.x,
y: offset.y,
}
: null,
};
}

Expand All @@ -97,7 +111,7 @@ export class PointerHandler {
this.pressed_ = true;

this.emitter.emit('down', {
data: this.computePosition_(...computeOffset(e, this.element)),
data: this.computePosition_(computeOffset(e, this.element)),
sender: this,
});
}
Expand All @@ -108,7 +122,7 @@ export class PointerHandler {
}

this.emitter.emit('move', {
data: this.computePosition_(...computeOffset(e, this.element)),
data: this.computePosition_(computeOffset(e, this.element)),
sender: this,
});
}
Expand All @@ -120,7 +134,7 @@ export class PointerHandler {
this.pressed_ = false;

this.emitter.emit('up', {
data: this.computePosition_(...computeOffset(e, this.element)),
data: this.computePosition_(computeOffset(e, this.element)),
sender: this,
});
}
Expand All @@ -129,24 +143,48 @@ export class PointerHandler {
// Prevent native page scroll
e.preventDefault();

const touch = e.targetTouches[0];
const touch = e.targetTouches.item(0);
const rect = this.element.getBoundingClientRect();
this.emitter.emit('down', {
data: this.computePosition_(
touch.clientX - rect.left,
touch.clientY - rect.top,
touch
? {
x: touch.clientX - rect.left,
y: touch.clientY - rect.top,
}
: undefined,
),
sender: this,
});
}

private onTouchMove_(e: TouchEvent) {
const touch = e.targetTouches[0];
const touch = e.targetTouches.item(0);
const rect = this.element.getBoundingClientRect();
this.emitter.emit('move', {
data: this.computePosition_(
touch.clientX - rect.left,
touch.clientY - rect.top,
touch
? {
x: touch.clientX - rect.left,
y: touch.clientY - rect.top,
}
: undefined,
),
sender: this,
});
}

private onTouchEnd_(e: TouchEvent) {
const touch = e.targetTouches.item(0);
const rect = this.element.getBoundingClientRect();
this.emitter.emit('up', {
data: this.computePosition_(
touch
? {
x: touch.clientX - rect.left,
y: touch.clientY - rect.top,
}
: undefined,
),
sender: this,
});
Expand Down
6 changes: 5 additions & 1 deletion lib/plugin/input-bindings/color/controller/a-palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ export class APaletteController implements ValueController<Color> {
}

private handlePointerEvent_(d: PointerData): void {
const alpha = d.x / d.bounds.width;
if (!d.point) {
return;
}

const alpha = d.point.x / d.bounds.width;

const c = this.value.rawValue;
const [h, s, v] = c.getComponents('hsv');
Expand Down
13 changes: 8 additions & 5 deletions lib/plugin/input-bindings/color/controller/color-picker.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {RangeConstraint} from '../../../common/constraint/range';
import {ValueController} from '../../../common/controller/value';
import {
createNumberFormatter,
Expand All @@ -6,8 +7,7 @@ import {
import {findNextTarget, supportsTouch} from '../../../common/dom-util';
import {Foldable} from '../../../common/model/foldable';
import {Value} from '../../../common/model/value';
import {connect} from '../../../common/model/value-sync';
import {TextController} from '../../common/controller/text';
import {connectValues} from '../../../common/model/value-sync';
import {NumberTextController} from '../../number/controller/number-text';
import {PickedColor} from '..//model/picked-color';
import {Color} from '../model/color';
Expand All @@ -32,7 +32,7 @@ export class ColorPickerController implements ValueController<Color> {
public triggerElement: HTMLElement | null = null;
private alphaIcs_: {
palette: APaletteController;
text: TextController<number>;
text: NumberTextController;
} | null;
private hPaletteIc_: HPaletteController;
private svPaletteIc_: SvPaletteController;
Expand All @@ -57,15 +57,18 @@ export class ColorPickerController implements ValueController<Color> {
value: this.pickedColor.value,
}),
text: new NumberTextController(doc, {
draggingScale: 0.01,
formatter: createNumberFormatter(2),
parser: parseNumber,
baseStep: 0.1,
value: new Value(0),
value: new Value(0, {
constraint: new RangeConstraint({min: 0, max: 1}),
}),
}),
}
: null;
if (this.alphaIcs_) {
connect({
connectValues({
primary: this.pickedColor.value,
secondary: this.alphaIcs_.text.value,
forward: (p) => {
Expand Down
10 changes: 5 additions & 5 deletions lib/plugin/input-bindings/color/controller/color-text-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ describe(ColorTextController.name, () => {
},
},
{
expected: {r: 0, g: 0, b: 1, a: 1},
expected: {r: 12, g: 34, b: 0, a: 1},
params: {
components: [0, 0, 1],
components: [12, 34, 56],
index: 2,
value: '1',
value: '0',
},
},
] as ChangeTestCase[]).forEach((testCase) => {
Expand All @@ -76,7 +76,7 @@ describe(ColorTextController.name, () => {
pickedColor: new PickedColor(value),
});

const inputElem = c.view.inputElements[testCase.params.index];
const inputElem = c.view.textViews[testCase.params.index].inputElement;
inputElem.value = testCase.params.value;
inputElem.dispatchEvent(TestUtil.createEvent(win, 'change'));
});
Expand Down Expand Up @@ -138,7 +138,7 @@ describe(ColorTextController.name, () => {
pickedColor: new PickedColor(value),
});

const inputElem = c.view.inputElements[testCase.params.index];
const inputElem = c.view.textViews[testCase.params.index].inputElement;
inputElem.dispatchEvent(
TestUtil.createKeyboardEvent(win, 'keydown', {
keyCode: testCase.params.keys.code,
Expand Down
Loading

0 comments on commit 151f230

Please sign in to comment.