All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.interacto.jfx.binding.KeysBinder Maven / Gradle / Ivy

The newest version!
/*
 * Interacto
 * Copyright (C) 2020 Arnaud Blouin
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see .
 */
package io.github.interacto.jfx.binding;

import io.github.interacto.command.Command;
import io.github.interacto.jfx.binding.api.KeyInteractionBinder;
import io.github.interacto.jfx.binding.api.KeyInteractionCmdBinder;
import io.github.interacto.jfx.binding.api.LogLevel;
import io.github.interacto.jfx.instrument.JfxInstrument;
import io.github.interacto.jfx.interaction.help.HelpAnimation;
import io.github.interacto.jfx.interaction.library.KeysData;
import io.github.interacto.jfx.interaction.library.KeysPressed;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;

/**
 * The base binding builder to create bindings between a keys pressure interaction and a given command.
 * @param  The type of the command to produce.
 * @param  The type of the widget to bind.
 * @author Arnaud Blouin
 */
abstract class KeysBinder extends Binder implements
				KeyInteractionBinder, KeyInteractionCmdBinder {
	Collection codes;
	final Predicate checkCode;
	boolean shift;
	boolean ctrl;
	boolean alt;
	boolean shortcut;
	boolean meta;


	KeysBinder(final JfxInstrument instrument, final BindingsObserver observer) {
		this(null, null, null, Collections.emptyList(),
			instrument, false, null, Collections.emptyList(), EnumSet.noneOf(LogLevel.class),
			null, false, null, null, null, Collections.emptyList(), null, null, null, observer, false);
	}

	KeysBinder(final BiConsumer initCmd, final Predicate whenPredicate, final Function cmdProducer,
		final List widgets, final JfxInstrument instrument, final boolean async,
		final BiConsumer onEnd, final List> additionalWidgets, final EnumSet logLevels,
		final HelpAnimation helpAnimation, final boolean withHelp, final DoubleProperty progressProp, final StringProperty msgProp, final Button cancel,
		final Collection keyCodes, final BiConsumer hadNoEffectFct, final BiConsumer hadEffectsFct,
		final BiConsumer cannotExecFct, final BindingsObserver observer, final boolean consumeEvents) {
		super(initCmd, whenPredicate, cmdProducer, widgets, KeysPressed::new, instrument, async, onEnd, additionalWidgets, logLevels, helpAnimation,
			withHelp, progressProp, msgProp, cancel, hadNoEffectFct, hadEffectsFct, cannotExecFct, observer, consumeEvents);
		setUpKeys(keyCodes);
		checkCode = i -> isCodeChecked(i) && (checkConditions == null || checkConditions.test(i));
	}

	private boolean isCodeChecked(final KeysData data) {
		final List keys = data.getKeyCodes();
		return (codes.isEmpty() || codes.size() == keys.size() && keys.containsAll(codes)) && isModifiersChecks(data);
	}

	private boolean isModifiersChecks(final KeysData data) {
		return meta == data.isMetaDown()
			&& alt == data.isAltDown()
			&& (!shortcut || data.isShortcutDown())
			&& shift == data.isShiftDown()
			&& ctrl == data.isCtrlDown();
	}

	private void setUpKeys(final Collection keys) {
		final var isMac = System.getProperty("os.name").startsWith("Mac");

		codes = keys
			.stream()
			.filter(key -> !key.isModifierKey() && key != KeyCode.SHORTCUT)
			.collect(Collectors.toUnmodifiableSet());
		shortcut = keys.contains(KeyCode.SHORTCUT);
		meta = keys.contains(KeyCode.META) || keys.contains(KeyCode.COMMAND) || (shortcut && isMac);
		shift = keys.contains(KeyCode.SHIFT);
		ctrl = keys.contains(KeyCode.CONTROL) || (shortcut && !isMac);
		alt = keys.contains(KeyCode.ALT);
	}

	@Override
	protected abstract KeysBinder duplicate();

	@Override
	public KeysBinder with(final KeyCode... keyCodes) {
		final KeysBinder dup = duplicate();
		dup.setUpKeys(Arrays.asList(keyCodes));
		return dup;
	}

	@Override
	public KeysBinder on(final W... widget) {
		return (KeysBinder) super.on(widget);
	}

	@Override
	public KeysBinder on(final ObservableList widgets) {
		return (KeysBinder) super.on(widgets);
	}

	@Override
	public KeysBinder first(final Consumer initCmdFct) {
		return (KeysBinder) super.first(initCmdFct);
	}

	@Override
	public KeysBinder first(final BiConsumer initCmdFct) {
		return (KeysBinder) super.first(initCmdFct);
	}

	@Override
	public KeysBinder when(final Predicate checkCmd) {
		return (KeysBinder) super.when(checkCmd);
	}

	@Override
	public KeysBinder when(final BooleanSupplier checkCmd) {
		return when(i -> checkCmd.getAsBoolean());
	}

	@Override
	public KeysBinder consume() {
		return (KeysBinder) super.consume();
	}

	@Override
	public KeysBinder async(final Button cancel, final DoubleProperty progressProp, final StringProperty msgProp) {
		return (KeysBinder) super.async(cancel, progressProp, msgProp);
	}

	@Override
	public KeysBinder ifHadEffects(final BiConsumer hadEffectsFct) {
		return (KeysBinder) super.ifHadEffects(hadEffectsFct);
	}

	@Override
	public KeysBinder ifHadNoEffect(final BiConsumer noEffectFct) {
		return (KeysBinder) super.ifHadNoEffect(noEffectFct);
	}

	@Override
	public KeysBinder end(final Consumer onEnd) {
		return (KeysBinder) super.end(onEnd);
	}

	@Override
	public KeysBinder end(final Runnable endFct) {
		return (KeysBinder) super.end(endFct);
	}

	@Override
	public KeysBinder end(final BiConsumer onEndFct) {
		return (KeysBinder) super.end(onEndFct);
	}

	@Override
	public KeysBinder log(final LogLevel... level) {
		return (KeysBinder) super.log(level);
	}

	@Override
	public KeysBinder help(final HelpAnimation animation) {
		return (KeysBinder) super.help(animation);
	}

	@Override
	public KeysBinder help(final Pane helpPane) {
		return (KeysBinder) super.help(helpPane);
	}

	@Override
	public  KeysBinder toProduce(final Supplier cmdCreation) {
		return (KeysBinder) super.toProduce(cmdCreation);
	}

	@Override
	public  KeysBinder toProduce(final Function cmdCreation) {
		return (KeysBinder) super.toProduce(cmdCreation);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy