001/* [{
002Copyright 2007, 2008, 2009 Nicolas Carranza <nicarran at gmail.com>
003
004This file is part of jpen.
005
006jpen is free software: you can redistribute it and/or modify
007it under the terms of the GNU Lesser General Public License as published by
008the Free Software Foundation, either version 3 of the License,
009or (at your option) any later version.
010
011jpen is distributed in the hope that it will be useful,
012but WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014GNU Lesser General Public License for more details.
015
016You should have received a copy of the GNU Lesser General Public License
017along with jpen.  If not, see <http://www.gnu.org/licenses/>.
018}] */
019package jpen;
020
021import java.util.ArrayList;
022import java.util.BitSet;
023import java.util.Collections;
024import java.util.List;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027import jpen.PButton;
028import jpen.PKind;
029
030public final class PLevelEmulator{
031        static final Logger L=Logger.getLogger(PLevelEmulator.class.getName());
032        //static { L.setLevel(Level.ALL); }
033
034        public static class ButtonTriggerPolicy{
035                public final int levelType;
036                public final float onPressValue;
037                public final float onReleaseValue;
038
039                public ButtonTriggerPolicy(PLevel.Type levelType, float onPressValue, float onReleaseValue){
040                        this(levelType.ordinal(), onPressValue, onReleaseValue);
041                }
042
043                public ButtonTriggerPolicy(int levelType, float onPressValue, float onReleaseValue){
044                        this.levelType=levelType;
045                        this.onPressValue=onPressValue;
046                        this.onReleaseValue=onReleaseValue;
047                }
048
049                @Override
050                public String toString(){
051                        return "( levelType="+levelType+", onPressValue="+onPressValue+", onReleaseValue="+onReleaseValue+" )";
052                }
053        }
054
055        final Pen pen;
056
057        PLevelEmulator(Pen pen){
058                this.pen=pen;
059        }
060
061        private final List<List<ButtonTriggerPolicy>> kindTypeToButtonTypeToButtonTriggerPolicy=new ArrayList<List<ButtonTriggerPolicy>>();
062        private final List<ButtonTriggerPolicy> activeButtonTriggerPolicies=new ArrayList<ButtonTriggerPolicy>();
063        private final BitSet activeLevelTypes=new BitSet();
064        private final List<ButtonTriggerPolicy> kindTypeToAlwaysActiveButtonTriggerPolicy=new ArrayList<ButtonTriggerPolicy>();
065
066        public void setPressureTriggerForLeftCursorButton(float pressure){
067                setTriggerForLeftCursorButton(new ButtonTriggerPolicy(PLevel.Type.PRESSURE.ordinal(),pressure,0f));
068        }
069
070        public void setTriggerForLeftCursorButton(ButtonTriggerPolicy triggerPolicy){
071                setTrigger(PKind.Type.CURSOR.ordinal(), PButton.Type.LEFT.ordinal(), triggerPolicy, true);
072        }
073
074        public void setTrigger(PKind.Type kindType, PButton.Type buttonType, ButtonTriggerPolicy triggerPolicy){
075                setTrigger(kindType.ordinal(), buttonType.ordinal(), triggerPolicy);
076        }
077
078        public synchronized void setTrigger(int kindType, int buttonType, ButtonTriggerPolicy triggerPolicy){
079                setTrigger(kindType, buttonType, triggerPolicy, false);
080        }
081
082        public synchronized void setTrigger(int kindType, int buttonType, ButtonTriggerPolicy triggerPolicy, boolean alwaysActiveOnKind){
083                List<ButtonTriggerPolicy> buttonTypeToButtonTriggerPolicy=getButtonTypeToButtonTriggerPolicy(kindType);
084                ensureListSize(buttonTypeToButtonTriggerPolicy, buttonType);
085                ButtonTriggerPolicy oldPolicy=buttonTypeToButtonTriggerPolicy.set(buttonType, triggerPolicy);
086
087                ensureListSize(kindTypeToAlwaysActiveButtonTriggerPolicy, kindType);
088                if(oldPolicy!=null){
089                        if(kindTypeToAlwaysActiveButtonTriggerPolicy.get(kindType)==oldPolicy)
090                                kindTypeToAlwaysActiveButtonTriggerPolicy.set(kindType, null);
091                }
092                if(triggerPolicy!=null && alwaysActiveOnKind){
093                        kindTypeToAlwaysActiveButtonTriggerPolicy.set(kindType, triggerPolicy);
094                }
095        }
096
097        public ButtonTriggerPolicy getButtonTriggerPolicy(PKind.Type kindType, PButton.Type buttonType){
098                return getButtonTriggerPolicy(kindType, buttonType);
099        }
100
101        public synchronized ButtonTriggerPolicy getButtonTriggerPolicy(int kindType, int buttonType){
102                List<ButtonTriggerPolicy> buttonTypeToButtonTriggerPolicy=getButtonTypeToButtonTriggerPolicy(kindType);
103                ensureListSize(buttonTypeToButtonTriggerPolicy, buttonType);
104                return buttonTypeToButtonTriggerPolicy.get(buttonType);
105        }
106
107        private List<ButtonTriggerPolicy> getButtonTypeToButtonTriggerPolicy(int kindType){
108                ensureListSize(kindTypeToButtonTypeToButtonTriggerPolicy, kindType);
109                List<ButtonTriggerPolicy> buttonTypeToButtonTriggerPolicy=kindTypeToButtonTypeToButtonTriggerPolicy.get(kindType);
110                if(buttonTypeToButtonTriggerPolicy==null){
111                        kindTypeToButtonTypeToButtonTriggerPolicy.set(kindType, buttonTypeToButtonTriggerPolicy=new ArrayList<ButtonTriggerPolicy>());
112                }
113                return buttonTypeToButtonTriggerPolicy;
114        }
115
116        private static void ensureListSize(List<?> list, int index){
117                while(list.size()<=index)
118                        list.add(null);
119        }
120
121        void scheduleEmulatedEvent(PButtonEvent buttonEvent){
122                PLevel emulatedLevel=null;
123                if(buttonEvent.button.value)
124                        emulatedLevel=emulateOnPress(buttonEvent.button.typeNumber);
125                else
126                        emulatedLevel=emulateOnRelease(buttonEvent.button.typeNumber);
127                if(emulatedLevel!=null){
128                        pen.penManager.scheduleLevelEvent(pen.penManager.emulationDevice, buttonEvent.time, Collections.singleton(emulatedLevel));
129                }
130        }
131
132        private PLevel emulateOnPress(int buttonType){
133                PenState lastScheduledState=pen.lastScheduledState;
134                ButtonTriggerPolicy triggerPolicy=getButtonTriggerPolicy(
135                                        lastScheduledState.getKind().typeNumber,
136                                        buttonType);
137                if(L.isLoggable(Level.FINE)) L.fine("triggerPolicy: "+triggerPolicy+", buttonType: "+buttonType);
138                if(triggerPolicy!=null){
139                        setActiveButtonTriggerPolicy(buttonType, triggerPolicy);
140                        if(lastScheduledState.getLevelValue(triggerPolicy.levelType)==
141                                 triggerPolicy.onPressValue)
142                                return null;
143                        return new PLevel(triggerPolicy.levelType, triggerPolicy.onPressValue);
144                }
145                return null;
146        }
147
148        private void setActiveButtonTriggerPolicy(int buttonType, ButtonTriggerPolicy policy){
149                ensureListSize(activeButtonTriggerPolicies, buttonType);
150                ButtonTriggerPolicy oldPolicy=activeButtonTriggerPolicies.set(buttonType, policy);
151                if(oldPolicy!=null){
152                        activeLevelTypes.set(oldPolicy.levelType, false);
153                }
154                if(policy!=null){
155                        activeLevelTypes.set(policy.levelType, true);
156                }
157        }
158
159        private PLevel emulateOnRelease(int buttonType){
160                ensureListSize(activeButtonTriggerPolicies, buttonType);
161                ButtonTriggerPolicy triggerPolicy=getActiveButtonTriggerPolicy(buttonType);
162                if(L.isLoggable(Level.FINE)) L.fine("triggerPolicy: "+triggerPolicy+", buttonType: "+buttonType);
163                if(triggerPolicy!=null){
164                        setActiveButtonTriggerPolicy(buttonType, null);
165                        PLevel pLevel=new PLevel(triggerPolicy.levelType, triggerPolicy.onReleaseValue);
166                        return pLevel;
167                }
168                return null;
169        }
170
171        private ButtonTriggerPolicy getActiveButtonTriggerPolicy(int buttonType){
172                ensureListSize(activeButtonTriggerPolicies, buttonType);
173                ButtonTriggerPolicy buttonTriggerPolicy=activeButtonTriggerPolicies.get(buttonType);
174                return buttonTriggerPolicy;
175        }
176
177        boolean onActivePolicy(int kindType, int levelType){
178                return onAlwaysActivePolicy(kindType, levelType) || activeLevelTypes.get(levelType);
179        }
180
181        private boolean onAlwaysActivePolicy(int kindType, int levelType){
182                ensureListSize(kindTypeToAlwaysActiveButtonTriggerPolicy, kindType);
183                ButtonTriggerPolicy alwaysActivePolicy=kindTypeToAlwaysActiveButtonTriggerPolicy.get(kindType);
184                return alwaysActivePolicy==null ? false :
185                                         alwaysActivePolicy.levelType==levelType;
186        }
187}