├── .gitignore ├── README.md ├── android ├── AndroidManifest.xml ├── assets │ ├── launcher.png │ ├── music.jpg │ ├── vedio.jpg │ └── weather.jpg ├── build.gradle ├── ic_launcher-web.png ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── meizu │ └── taskmanager │ └── android │ └── AndroidLauncher.java ├── build.gradle ├── core ├── build.gradle └── src │ ├── TaskManager.gwt.xml │ └── com │ └── meizu │ └── taskmanager │ ├── PagerStage.java │ ├── TaskActor.java │ ├── TaskItem.java │ ├── TaskManager.java │ ├── policy │ ├── BackgroundService.java │ └── ManagerService.java │ ├── ui │ ├── HorizontalGroup.java │ └── ScrollPane.java │ └── utils │ ├── action │ └── CancelableAction.java │ ├── animation │ ├── FloatEvaluator.java │ ├── IntEvaluator.java │ └── TypeEvaluator.java │ └── eventbus │ └── EventBusUtil.java ├── desktop ├── build.gradle └── src │ └── com │ └── meizu │ └── taskmanager │ └── desktop │ └── DesktopLauncher.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── html ├── build.gradle ├── src │ └── com │ │ └── meizu │ │ └── taskmanager │ │ ├── GdxDefinition.gwt.xml │ │ ├── GdxDefinitionSuperdev.gwt.xml │ │ └── client │ │ └── HtmlLauncher.java └── webapp │ ├── WEB-INF │ └── web.xml │ ├── index.html │ ├── refresh.png │ ├── soundmanager2-jsmin.js │ ├── soundmanager2-setup.js │ └── styles.css ├── screen-record.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ## Java 2 | 3 | *.class 4 | *.war 5 | *.ear 6 | hs_err_pid* 7 | 8 | ## GWT 9 | war/ 10 | html/war/gwt_bree/ 11 | html/gwt-unitCache/ 12 | .apt_generated/ 13 | html/war/WEB-INF/deploy/ 14 | html/war/WEB-INF/classes/ 15 | .gwt/ 16 | gwt-unitCache/ 17 | www-test/ 18 | .gwt-tmp/ 19 | 20 | ## Android Studio and Intellij and Android in general 21 | android/libs/armeabi/ 22 | android/libs/armeabi-v7a/ 23 | android/libs/x86/ 24 | android/gen/ 25 | .idea/ 26 | *.ipr 27 | *.iws 28 | *.iml 29 | out/ 30 | com_crashlytics_export_strings.xml 31 | 32 | ## Eclipse 33 | .classpath 34 | .project 35 | .metadata 36 | **/bin/ 37 | tmp/ 38 | *.tmp 39 | *.bak 40 | *.swp 41 | *~.nib 42 | local.properties 43 | .settings/ 44 | .loadpath 45 | .externalToolBuilders/ 46 | *.launch 47 | 48 | ## NetBeans 49 | **/nbproject/private/ 50 | build/ 51 | nbbuild/ 52 | dist/ 53 | nbdist/ 54 | nbactions.xml 55 | nb-configuration.xml 56 | 57 | ## Gradle 58 | 59 | .gradle 60 | gradle-app.setting 61 | build/ 62 | 63 | ## OS Specific 64 | .DS_Store 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TaskManager 2 | 3 | ---- 4 | 5 | ![gif](screen-record.gif) 6 | 7 | 恕我脑残,之前移除了对桌面应用的支持。重新加回桌面应用的支持和html的支持! 8 | 9 | 初步规则如下: 10 | 11 | 1、优先在桌面应用的模式下进行调试,效率大幅提升(cd desktop && gradle runDesktop); 12 | 13 | 2、所有的代码放于core目录下; 14 | 15 | 3、用core下的policy目录模拟多任务的真实场景,后期再迁回android/desktop/html目录; 16 | 17 | 18 | running or debugging: 19 | 20 | Desktop: Run -> Edit Configurations..., click the plus (+) button and select Application. Set the Nameto Desktop.Set the field Use classpath of module to desktop, then click on the button of the Main class field and select the DesktopLauncher class. Set the Working directory to your android/assets/ (or your_project_path/core/assets/) folder! Click Apply and then OK. You have now created a run configuration for your desktop project. You can now select the configuration and run it. 21 | 22 | Android: A configuration for the Android project should be automatically created on project import. As such, you only have to select the configuration and run it! 23 | 24 | iOS: Run -> Edit Configurations..., click the plus (+) button and select Gradle. Set the Name to iOS, set the Gradle Project to ios, set the Tasks to launchIPhoneSimulator (alternatives are launchIPadSimulator and launchIOSDevicefor provisioned devices). Click Apply and then OK. You have now created a run configuration for your iOS project. You can now select the configuration and run it. The first run will take a bit longer as RoboVM has to compile the entire JDK for iOS. Subsequent runs will compile considerably faster! 25 | 26 | HTML: View -> Tool Window -> Terminal, in the terminal, make sure you are in the root folder of your project. Then execute gradlew.bat html:superDev (Windows) or ./gradlew html:superDev (Linux, Mac OS X). This will take a while, as your Java code is compiled to Javascript. Once you see the message The code server is ready, fire up your browser and go to http://localhost:8080/html. This is your app running in the browser! When you change any of your Java code or assets, just click the SuperDev refresh button while you are on the site and the server will recompile your code and reload the page! To kill the process, simply press CTRL + C in the terminal window. 27 | -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/assets/launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/assets/launcher.png -------------------------------------------------------------------------------- /android/assets/music.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/assets/music.jpg -------------------------------------------------------------------------------- /android/assets/vedio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/assets/vedio.jpg -------------------------------------------------------------------------------- /android/assets/weather.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/assets/weather.jpg -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | android { 2 | buildToolsVersion "21.1.2" 3 | compileSdkVersion 21 4 | sourceSets { 5 | main { 6 | manifest.srcFile 'AndroidManifest.xml' 7 | java.srcDirs = ['src'] 8 | aidl.srcDirs = ['src'] 9 | renderscript.srcDirs = ['src'] 10 | res.srcDirs = ['res'] 11 | assets.srcDirs = ['assets'] 12 | } 13 | 14 | instrumentTest.setRoot('tests') 15 | } 16 | } 17 | 18 | // needed to add JNI shared libraries to APK when compiling on CLI 19 | tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask -> 20 | pkgTask.jniFolders = new HashSet() 21 | pkgTask.jniFolders.add(new File(projectDir, 'libs')) 22 | } 23 | 24 | // called every time gradle gets executed, takes the native dependencies of 25 | // the natives configuration, and extracts them to the proper libs/ folders 26 | // so they get packed with the APK. 27 | task copyAndroidNatives() { 28 | file("libs/armeabi/").mkdirs(); 29 | file("libs/armeabi-v7a/").mkdirs(); 30 | file("libs/x86/").mkdirs(); 31 | 32 | configurations.natives.files.each { jar -> 33 | def outputDir = null 34 | if(jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a") 35 | if(jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi") 36 | if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86") 37 | if(outputDir != null) { 38 | copy { 39 | from zipTree(jar) 40 | into outputDir 41 | include "*.so" 42 | } 43 | } 44 | } 45 | } 46 | 47 | task run(type: Exec) { 48 | def path 49 | def localProperties = project.file("../local.properties") 50 | if (localProperties.exists()) { 51 | Properties properties = new Properties() 52 | localProperties.withInputStream { instr -> 53 | properties.load(instr) 54 | } 55 | def sdkDir = properties.getProperty('sdk.dir') 56 | if (sdkDir) { 57 | path = sdkDir 58 | } else { 59 | path = "$System.env.ANDROID_HOME" 60 | } 61 | } else { 62 | path = "$System.env.ANDROID_HOME" 63 | } 64 | 65 | def adb = path + "/platform-tools/adb" 66 | commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.meizu.taskmanager.android/com.meizu.taskmanager.android.AndroidLauncher' 67 | } 68 | 69 | // sets up the Android Eclipse project, using the old Ant based build. 70 | eclipse { 71 | // need to specify Java source sets explicitely, SpringSource Gradle Eclipse plugin 72 | // ignores any nodes added in classpath.file.withXml 73 | sourceSets { 74 | main { 75 | java.srcDirs "src", 'gen' 76 | } 77 | } 78 | 79 | jdt { 80 | sourceCompatibility = 1.6 81 | targetCompatibility = 1.6 82 | } 83 | 84 | classpath { 85 | plusConfigurations += [ project.configurations.compile ] 86 | containers 'com.android.ide.eclipse.adt.ANDROID_FRAMEWORK', 'com.android.ide.eclipse.adt.LIBRARIES' 87 | } 88 | 89 | project { 90 | name = appName + "-android" 91 | natures 'com.android.ide.eclipse.adt.AndroidNature' 92 | buildCommands.clear(); 93 | buildCommand "com.android.ide.eclipse.adt.ResourceManagerBuilder" 94 | buildCommand "com.android.ide.eclipse.adt.PreCompilerBuilder" 95 | buildCommand "org.eclipse.jdt.core.javabuilder" 96 | buildCommand "com.android.ide.eclipse.adt.ApkBuilder" 97 | } 98 | } 99 | 100 | // sets up the Android Idea project, using the old Ant based build. 101 | idea { 102 | module { 103 | sourceDirs += file("src"); 104 | scopes = [ COMPILE: [plus:[project.configurations.compile]]] 105 | 106 | iml { 107 | withXml { 108 | def node = it.asNode() 109 | def builder = NodeBuilder.newInstance(); 110 | builder.current = node; 111 | builder.component(name: "FacetManager") { 112 | facet(type: "android", name: "Android") { 113 | configuration { 114 | option(name: "UPDATE_PROPERTY_FILES", value:"true") 115 | } 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /android/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/ic_launcher-web.png -------------------------------------------------------------------------------- /android/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | 22 | -verbose 23 | 24 | -dontwarn android.support.** 25 | -dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication 26 | -dontwarn com.badlogic.gdx.utils.GdxBuild 27 | -dontwarn com.badlogic.gdx.physics.box2d.utils.Box2DBuild 28 | -dontwarn com.badlogic.gdx.jnigen.BuildTarget* 29 | 30 | -keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* { 31 | (com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration); 32 | } 33 | 34 | -keepclassmembers class com.badlogic.gdx.physics.box2d.World { 35 | boolean contactFilter(long, long); 36 | void beginContact(long); 37 | void endContact(long); 38 | void preSolve(long, long); 39 | void postSolve(long, long); 40 | boolean reportFixture(long); 41 | float reportRayFixture(long, float, float, float, float, float); 42 | } 43 | -------------------------------------------------------------------------------- /android/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /android/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/android/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TaskManager 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/src/com/meizu/taskmanager/android/AndroidLauncher.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.android; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.badlogic.gdx.backends.android.AndroidApplication; 6 | import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; 7 | import com.meizu.taskmanager.TaskManager; 8 | 9 | public class AndroidLauncher extends AndroidApplication { 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); 14 | config.disableAudio = true; 15 | config.useAccelerometer = false; 16 | config.useGLSurfaceView20API18 = true; 17 | initialize(new TaskManager(), config); 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'de.richsource.gradle.plugins:gwt-gradle-plugin:0.6' 8 | classpath 'com.android.tools.build:gradle:1.0.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | apply plugin: "eclipse" 14 | apply plugin: "idea" 15 | 16 | version = '1.0' 17 | ext { 18 | appName = 'TaskManager' 19 | gdxVersion = '1.5.3' 20 | roboVMVersion = '1.0.0-beta-03' 21 | box2DLightsVersion = '1.3' 22 | ashleyVersion = '1.3.1' 23 | aiVersion = '1.5.0' 24 | } 25 | 26 | repositories { 27 | mavenCentral() 28 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 29 | maven { url "https://oss.sonatype.org/content/repositories/releases/" } 30 | } 31 | } 32 | 33 | project(":desktop") { 34 | apply plugin: "java" 35 | 36 | 37 | dependencies { 38 | compile project(":core") 39 | compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" 40 | compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" 41 | compile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" 42 | } 43 | } 44 | 45 | project(":android") { 46 | apply plugin: "android" 47 | 48 | configurations { natives } 49 | 50 | dependencies { 51 | compile project(":core") 52 | compile "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" 53 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi" 54 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" 55 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" 56 | compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" 57 | natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi" 58 | natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a" 59 | natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86" 60 | } 61 | } 62 | 63 | project(":html") { 64 | apply plugin: "gwt" 65 | apply plugin: "war" 66 | 67 | 68 | dependencies { 69 | compile project(":core") 70 | compile "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion" 71 | compile "com.badlogicgames.gdx:gdx:$gdxVersion:sources" 72 | compile "com.badlogicgames.gdx:gdx-backend-gwt:$gdxVersion:sources" 73 | compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion:sources" 74 | compile "com.badlogicgames.gdx:gdx-box2d-gwt:$gdxVersion:sources" 75 | } 76 | } 77 | 78 | project(":core") { 79 | apply plugin: "java" 80 | 81 | 82 | dependencies { 83 | compile "com.badlogicgames.gdx:gdx:$gdxVersion" 84 | compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" 85 | compile "com.google.guava:guava:+" 86 | } 87 | } 88 | 89 | tasks.eclipse.doLast { 90 | delete ".project" 91 | } -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | 3 | sourceCompatibility = 1.7 4 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' 5 | 6 | sourceSets.main.java.srcDirs = [ "src/" ] 7 | 8 | 9 | eclipse.project { 10 | name = appName + "-core" 11 | } 12 | -------------------------------------------------------------------------------- /core/src/TaskManager.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/PagerStage.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.badlogic.gdx.input.GestureDetector; 5 | import com.badlogic.gdx.math.Interpolation; 6 | import com.badlogic.gdx.math.Vector2; 7 | import com.badlogic.gdx.scenes.scene2d.Action; 8 | import com.badlogic.gdx.scenes.scene2d.Actor; 9 | import com.badlogic.gdx.scenes.scene2d.Stage; 10 | import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction; 11 | import com.badlogic.gdx.utils.SnapshotArray; 12 | import com.google.common.eventbus.Subscribe; 13 | import com.meizu.taskmanager.ui.HorizontalGroup; 14 | import com.meizu.taskmanager.utils.action.CancelableAction; 15 | import com.meizu.taskmanager.utils.animation.FloatEvaluator; 16 | import com.meizu.taskmanager.utils.eventbus.EventBusUtil; 17 | 18 | 19 | public class PagerStage extends Stage { 20 | 21 | public final static class UpdateRectEvent { 22 | } 23 | 24 | public final static class Rect { 25 | public final float x; 26 | public final float y; 27 | public final float width; 28 | public final float height; 29 | public final float center; 30 | 31 | public Rect(float x, float y, float width, float height) { 32 | this.x = x; 33 | this.y = y; 34 | this.width = width; 35 | this.height = height; 36 | this.center = x + width / 2; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "Rect{" + 42 | "center=" + center + 43 | '}'; 44 | } 45 | } 46 | 47 | public GestureDetector.GestureListener flickScrollListener; 48 | 49 | private Rect[] mRect; 50 | private float mCameraPosition; 51 | private HorizontalGroup mGroup; 52 | private CancelableAction mMoveCameraAction; 53 | 54 | public PagerStage() { 55 | super(); 56 | mCameraPosition = getCamera().position.x; 57 | flickScrollListener = new GestureDetector.GestureListener() { 58 | short focusThis; 59 | 60 | @Override 61 | public boolean touchDown(float x, float y, int pointer, int button) { 62 | focusThis = 0; 63 | cancelMoveIfNeed(); 64 | return false; 65 | } 66 | 67 | @Override 68 | public boolean tap(float x, float y, int count, int button) { 69 | return false; 70 | } 71 | 72 | @Override 73 | public boolean longPress(float x, float y) { 74 | return false; 75 | } 76 | 77 | @Override 78 | public boolean fling(float velocityX, float velocityY, int button) { 79 | if (focusThis == 1) { 80 | addAction(new ScrollCameraAction(0.5f, Interpolation.linear).setToPotion(calm(mCameraPosition - velocityX))); 81 | return true; 82 | } 83 | return false; 84 | } 85 | 86 | @Override 87 | public boolean pan(float x, float y, float deltaX, float deltaY) { 88 | if (focusThis == 0) { 89 | if (Math.abs(deltaX) > Math.abs(deltaY)) { 90 | focusThis = 1; 91 | cancelTouchFocus(); 92 | return true; 93 | } else { 94 | focusThis = -1; 95 | return false; 96 | } 97 | 98 | } else if (focusThis == 1) { 99 | addAction(new MoveCameraAction().setOffset(-deltaX)); 100 | return true; 101 | } else { 102 | return false; 103 | } 104 | } 105 | 106 | @Override 107 | public boolean panStop(float x, float y, int pointer, int button) { 108 | if (focusThis == 1) { 109 | addAction(new ScrollCameraAction(0.2f, Interpolation.linear).setToPotion(calm(mCameraPosition))); 110 | return true; 111 | } else { 112 | return false; 113 | } 114 | } 115 | 116 | @Override 117 | public boolean zoom(float initialDistance, float distance) { 118 | return false; 119 | } 120 | 121 | @Override 122 | public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) { 123 | return false; 124 | } 125 | }; 126 | 127 | EventBusUtil.getDefaultEventBus().register(this); 128 | 129 | } 130 | 131 | @Override 132 | public void dispose() { 133 | super.dispose(); 134 | EventBusUtil.getDefaultEventBus().unregister(this); 135 | } 136 | 137 | public void bindGroup(HorizontalGroup group) { 138 | mGroup = group; 139 | } 140 | 141 | public float calm(float toPotion) { 142 | float reFloat = 0; 143 | float distance = Float.MAX_VALUE; 144 | for (int i = 0, n = mRect.length; i < n; i++) { 145 | final float dis = Math.abs(mRect[i].center - toPotion); 146 | if (dis < distance) { 147 | distance = dis; 148 | reFloat = mRect[i].center; 149 | } 150 | } 151 | return reFloat; 152 | } 153 | 154 | @Subscribe 155 | public void updateRect(UpdateRectEvent event) { 156 | updateRect(); 157 | } 158 | 159 | public void updateRect() { 160 | SnapshotArray children = mGroup.getChildren(); 161 | PagerStage.Rect[] rects = new PagerStage.Rect[children.size]; 162 | for (int i = 0, n = rects.length; i < n; i++) { 163 | Actor actor = children.get(i); 164 | 165 | rects[i] = new PagerStage.Rect(actor.getX(), actor.getY(), actor.getWidth(), actor.getHeight()); 166 | } 167 | mRect = rects; 168 | 169 | 170 | float calm = calm(mCameraPosition); 171 | if (calm != mCameraPosition) 172 | addAction(new ScrollCameraAction(0.2f, Interpolation.linear).setToPotion(calm)); 173 | } 174 | 175 | public void init() { 176 | addAction(new MoveCameraAction().setOffset(mRect[0].center - mCameraPosition)); 177 | } 178 | 179 | private void updateCameraToPotion(float toPotion) { 180 | mCameraPosition = toPotion; 181 | getCamera().position.set(mCameraPosition, Gdx.graphics.getHeight() / 2, getCamera().position.z); 182 | getCamera().update(); 183 | } 184 | 185 | private void updateCameraOffset(float x) { 186 | mCameraPosition += x; 187 | getCamera().position.set(mCameraPosition, Gdx.graphics.getHeight() / 2, getCamera().position.z); 188 | getCamera().update(); 189 | } 190 | 191 | 192 | private void cancelMoveIfNeed(){ 193 | if (mMoveCameraAction != null) { 194 | mMoveCameraAction.cancel(); 195 | } 196 | } 197 | 198 | private class MoveCameraAction extends Action { 199 | 200 | private float offset; 201 | 202 | public MoveCameraAction() { 203 | super(); 204 | cancelMoveIfNeed(); 205 | } 206 | 207 | public MoveCameraAction setOffset(float offset) { 208 | this.offset = offset; 209 | return this; 210 | } 211 | 212 | @Override 213 | public boolean act(float delta) { 214 | updateCameraOffset(offset); 215 | return true; 216 | } 217 | 218 | } 219 | 220 | private class ScrollCameraAction extends TemporalAction implements CancelableAction { 221 | 222 | FloatEvaluator floatEvaluator = new FloatEvaluator(); 223 | 224 | @Override 225 | protected void end() { 226 | if (mMoveCameraAction == this) mMoveCameraAction = null; 227 | } 228 | 229 | private boolean alive = true; 230 | 231 | private float toPotion; 232 | 233 | private float originPotion; 234 | 235 | ScrollCameraAction(float duration, Interpolation interpolation) { 236 | super(duration, interpolation); 237 | cancelMoveIfNeed(); 238 | mMoveCameraAction = this; 239 | } 240 | 241 | 242 | public ScrollCameraAction setToPotion(float toPotion) { 243 | this.originPotion = mCameraPosition; 244 | this.toPotion = toPotion; 245 | return this; 246 | } 247 | 248 | 249 | @Override 250 | protected void update(float percent) { 251 | if (!alive) return; 252 | updateCameraToPotion(floatEvaluator.evaluate(percent, originPotion, toPotion)); 253 | } 254 | 255 | @Override 256 | public void cancel() { 257 | alive = false; 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/TaskActor.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.badlogic.gdx.graphics.g2d.Batch; 5 | import com.badlogic.gdx.graphics.g2d.Sprite; 6 | import com.badlogic.gdx.scenes.scene2d.Action; 7 | import com.badlogic.gdx.scenes.scene2d.Actor; 8 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 9 | import com.badlogic.gdx.scenes.scene2d.Stage; 10 | import com.badlogic.gdx.scenes.scene2d.actions.MoveByAction; 11 | import com.badlogic.gdx.scenes.scene2d.actions.MoveToAction; 12 | import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener; 13 | import com.meizu.taskmanager.utils.action.CancelableAction; 14 | 15 | public class TaskActor extends Actor { 16 | private Sprite mSprite; 17 | 18 | private CancelableAction mMoveAction; 19 | 20 | public TaskActor(TaskItem item) { 21 | addCaptureListener(actorGestureListener); 22 | 23 | final float zoom = Gdx.graphics.getWidth() * 0.6f / item.getScreenShot().getWidth(); 24 | 25 | mSprite = new Sprite(item.getScreenShot()); 26 | mSprite.setSize(mSprite.getWidth() * zoom, mSprite.getHeight() * zoom); 27 | setWidth(mSprite.getWidth()); 28 | setHeight(mSprite.getHeight()); 29 | } 30 | 31 | @Override 32 | public void draw(Batch batch, float parentAlpha) { 33 | mSprite.setPosition(getX(), getY()); 34 | mSprite.draw(batch); 35 | } 36 | 37 | private ActorGestureListener actorGestureListener = new ActorGestureListener() { 38 | boolean catchFocus; 39 | float speed; 40 | 41 | @Override 42 | public void pan(InputEvent event, float x, float y, float deltaX, float deltaY) { 43 | Stage stage = getStage(); 44 | if (!catchFocus && Math.abs(deltaX) < Math.abs(deltaY)) { 45 | catchFocus = true; 46 | if (stage != null) 47 | stage.cancelTouchFocusExcept(actorGestureListener, TaskActor.this); 48 | } 49 | if (catchFocus) { 50 | MoveByAction moveByAction = new MoveByAction(); 51 | moveByAction.setAmountY(deltaY); 52 | addAction(moveByAction); 53 | } 54 | } 55 | 56 | @Override 57 | public void touchDown(InputEvent event, float x, float y, int pointer, int button) { 58 | speed = 0; 59 | cancelMoveIfNeed(); 60 | if (getOriginY() == 0) { 61 | setOriginY(getY()); 62 | } 63 | super.touchDown(event, x, y, pointer, button); 64 | } 65 | 66 | @Override 67 | public void touchUp(InputEvent event, float x, float y, int pointer, int button) { 68 | 69 | if ((Math.abs(speed) <= 150 && speed != 0) || (speed == 0 && getY() != getOriginY())) { 70 | MoveToOringinAction moveToAction = new MoveToOringinAction(); 71 | moveToAction.setPosition(getX(), getOriginY()); 72 | moveToAction.setDuration(0.5f); 73 | addAction(moveToAction); 74 | } 75 | super.touchUp(event, x, y, pointer, button); 76 | } 77 | 78 | @Override 79 | public void fling(InputEvent event, float velocityX, float velocityY, int button) { 80 | speed = velocityY; 81 | 82 | if (Math.abs(speed) > 150) { 83 | addAction(new RemoveTaskAction()); 84 | } else { 85 | MoveToOringinAction moveToAction = new MoveToOringinAction(); 86 | moveToAction.setPosition(getX(), getOriginY()); 87 | moveToAction.setDuration(0.3f); 88 | addAction(moveToAction); 89 | } 90 | super.fling(event, velocityX, velocityY, button); 91 | } 92 | }; 93 | 94 | 95 | private void cancelMoveIfNeed(){ 96 | if (mMoveAction != null) { 97 | mMoveAction.cancel(); 98 | } 99 | } 100 | 101 | private class MoveToOringinAction extends MoveToAction implements CancelableAction { 102 | boolean alive = true; 103 | 104 | public MoveToOringinAction() { 105 | cancelMoveIfNeed(); 106 | mMoveAction = this; 107 | } 108 | 109 | @Override 110 | protected void end() { 111 | if (mMoveAction == this) mMoveAction = null; 112 | } 113 | 114 | @Override 115 | protected void update(float percent) { 116 | if (!alive) return; 117 | super.update(percent); 118 | } 119 | 120 | @Override 121 | public void cancel() { 122 | alive = false; 123 | } 124 | } 125 | 126 | private class RemoveTaskAction extends Action { 127 | 128 | 129 | public boolean act(float delta) { 130 | target.remove(); 131 | return true; 132 | } 133 | 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/TaskItem.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager; 2 | 3 | import com.badlogic.gdx.graphics.Texture; 4 | 5 | public class TaskItem { 6 | private int id; 7 | private Texture screenShot; 8 | private Texture icon; 9 | 10 | public int getId() { 11 | return id; 12 | } 13 | 14 | public TaskItem setId(int id) { 15 | this.id = id; 16 | return this; 17 | } 18 | 19 | public Texture getScreenShot() { 20 | return screenShot; 21 | } 22 | 23 | public TaskItem setScreenShot(Texture screenShot) { 24 | this.screenShot = screenShot; 25 | return this; 26 | } 27 | 28 | public Texture getIcon() { 29 | return icon; 30 | } 31 | 32 | public TaskItem setIcon(Texture icon) { 33 | this.icon = icon; 34 | return this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/TaskManager.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager; 2 | 3 | import com.badlogic.gdx.ApplicationListener; 4 | import com.badlogic.gdx.Gdx; 5 | import com.badlogic.gdx.InputMultiplexer; 6 | import com.badlogic.gdx.graphics.GL30; 7 | import com.badlogic.gdx.graphics.g2d.SpriteBatch; 8 | import com.badlogic.gdx.input.GestureDetector; 9 | import com.meizu.taskmanager.policy.BackgroundService; 10 | import com.meizu.taskmanager.policy.ManagerService; 11 | import com.meizu.taskmanager.ui.HorizontalGroup; 12 | 13 | 14 | public class TaskManager implements ApplicationListener { 15 | private PagerStage mStage; 16 | private SpriteBatch mBatch; 17 | 18 | @Override 19 | public void create() { 20 | mBatch = new SpriteBatch(); 21 | mStage = new PagerStage(); 22 | 23 | Gdx.graphics.setContinuousRendering(true); 24 | 25 | InputMultiplexer multiplexer = new InputMultiplexer(new GestureDetector(mStage.flickScrollListener), mStage); 26 | Gdx.input.setInputProcessor(multiplexer); 27 | } 28 | 29 | @Override 30 | public void resize(int width, int height) { 31 | pause(); 32 | resume(); 33 | } 34 | 35 | @Override 36 | public void render() { 37 | Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT); 38 | 39 | mBatch.begin(); 40 | mBatch.draw(BackgroundService.getBackGround(), 0, 0); 41 | mBatch.end(); 42 | mStage.act(Gdx.graphics.getDeltaTime()); 43 | mStage.draw(); 44 | } 45 | 46 | @Override 47 | public void pause() { 48 | mStage.clear(); 49 | } 50 | 51 | @Override 52 | public void resume() { 53 | 54 | HorizontalGroup mGroup = new HorizontalGroup(); 55 | mGroup.space(50f); 56 | mGroup.setBounds(0, 0, mStage.getWidth(), mStage.getHeight()); 57 | final TaskItem[] taskItems = ManagerService.getTaskItem(); 58 | for (int i = 0; i < taskItems.length; i++) { 59 | mGroup.addActor(new TaskActor(taskItems[i])); 60 | } 61 | mGroup.layout(); 62 | mStage.addActor(mGroup); 63 | mStage.bindGroup(mGroup); 64 | mStage.updateRect(); 65 | mStage.init(); 66 | 67 | } 68 | 69 | @Override 70 | public void dispose() { 71 | mStage.dispose(); 72 | mStage = null; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/policy/BackgroundService.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.policy; 2 | 3 | import com.badlogic.gdx.graphics.Texture; 4 | 5 | public class BackgroundService { 6 | private static Texture background; 7 | 8 | public synchronized static final Texture getBackGround() { 9 | if (background == null) background = new Texture("launcher.png"); 10 | return background; 11 | } 12 | } -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/policy/ManagerService.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.policy; 2 | 3 | import com.badlogic.gdx.graphics.Texture; 4 | import com.meizu.taskmanager.TaskItem; 5 | 6 | public class ManagerService { 7 | static TaskItem[] taskItems; 8 | 9 | public static void kill(){ 10 | 11 | } 12 | 13 | public static TaskItem[] getTaskItem() { 14 | if (taskItems == null) { 15 | taskItems = new TaskItem[18]; 16 | Texture texture1 = new Texture("music.jpg"); 17 | Texture texture2 = new Texture("vedio.jpg"); 18 | Texture texture3 = new Texture("weather.jpg"); 19 | 20 | for (int i = 0; i < taskItems.length; i++) { 21 | double random = Math.random(); 22 | if (random < 0.3) { 23 | taskItems[i] = new TaskItem().setScreenShot(texture1); 24 | } else if (random < 0.6) { 25 | taskItems[i] = new TaskItem().setScreenShot(texture2); 26 | } else { 27 | taskItems[i] = new TaskItem().setScreenShot(texture3); 28 | } 29 | } 30 | } 31 | return taskItems; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/ui/HorizontalGroup.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.meizu.taskmanager.ui; 18 | 19 | import com.badlogic.gdx.math.Interpolation; 20 | import com.badlogic.gdx.scenes.scene2d.Actor; 21 | import com.badlogic.gdx.scenes.scene2d.Touchable; 22 | import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction; 23 | import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; 24 | import com.badlogic.gdx.scenes.scene2d.utils.Align; 25 | import com.badlogic.gdx.scenes.scene2d.utils.Layout; 26 | import com.badlogic.gdx.utils.SnapshotArray; 27 | import com.google.common.eventbus.EventBus; 28 | import com.meizu.taskmanager.PagerStage; 29 | import com.meizu.taskmanager.utils.eventbus.EventBusUtil; 30 | 31 | /** A group that lays out its children side by side in a single row. This can be easier than using {@link com.badlogic.gdx.scenes.scene2d.ui.Table} when actors need 32 | * to be inserted in the middle of the group. 33 | *

34 | * The preferred width is the sum of the children's preferred widths, plus spacing if set. The preferred height is the largest 35 | * preferred height of any child. The min size is the preferred size and the max size is 0 as HorizontalGroup can be 36 | * stretched to cover any area. 37 | *

38 | * This UI widget does not support Layoutable actors that return 0 as their preferred width. A fine example is 39 | * {@link com.badlogic.gdx.scenes.scene2d.ui.Label} class with text wrapping turned on. 40 | * @author Nathan Sweet */ 41 | public class HorizontalGroup extends WidgetGroup { 42 | private float prefWidth, prefHeight; 43 | private boolean sizeInvalid = true; 44 | private int align; 45 | private boolean reverse, round = true; 46 | private float spacing; 47 | private float padTop, padLeft, padBottom, padRight; 48 | private float fill; 49 | 50 | public HorizontalGroup () { 51 | setTouchable(Touchable.childrenOnly); 52 | } 53 | 54 | public void invalidate () { 55 | super.invalidate(); 56 | sizeInvalid = true; 57 | } 58 | 59 | private void computeSize () { 60 | sizeInvalid = false; 61 | SnapshotArray children = getChildren(); 62 | int n = children.size; 63 | prefWidth = padLeft + padRight + spacing * (n - 1); 64 | prefHeight = 0; 65 | for (int i = 0; i < n; i++) { 66 | Actor child = children.get(i); 67 | if (child instanceof Layout) { 68 | Layout layout = (Layout)child; 69 | prefWidth += layout.getPrefWidth(); 70 | prefHeight = Math.max(prefHeight, layout.getPrefHeight()); 71 | } else { 72 | prefWidth += child.getWidth(); 73 | prefHeight = Math.max(prefHeight, child.getHeight()); 74 | } 75 | } 76 | prefHeight += padTop + padBottom; 77 | if (round) { 78 | prefWidth = Math.round(prefWidth); 79 | prefHeight = Math.round(prefHeight); 80 | } 81 | } 82 | 83 | int mChildNumber =0; 84 | @Override 85 | protected void childrenChanged() { 86 | int locChildNumber = getChildren().size; 87 | if(locChildNumber children = getChildren(); 124 | 125 | @Override 126 | protected void begin() { 127 | super.begin(); 128 | fromX=new float[children.size]; 129 | toX=new float[children.size]; 130 | for(int i = 0, n = children.size; i < n; i++){ 131 | Actor child=children.get(i); 132 | fromX[i]=child.getX(); 133 | 134 | float width, height; 135 | if (child instanceof Layout) { 136 | Layout layout = (Layout)child; 137 | if (fill > 0) 138 | height = groupHeight * fill; 139 | else 140 | height = Math.min(layout.getPrefHeight(), groupHeight); 141 | height = Math.max(height, layout.getMinHeight()); 142 | float maxHeight = layout.getMaxHeight(); 143 | if (maxHeight > 0 && height > maxHeight) height = maxHeight; 144 | width = layout.getPrefWidth(); 145 | } else { 146 | width = child.getWidth(); 147 | height = child.getHeight(); 148 | if (fill > 0) height *= fill; 149 | } 150 | 151 | float y = padBottom; 152 | if ((align & Align.top) != 0) 153 | y += groupHeight - height; 154 | else if ((align & Align.bottom) == 0) // center 155 | y += (groupHeight - height) / 2; 156 | 157 | if (reverse) x -= (width + spacing); 158 | if (round) 159 | toX[i]=Math.round(x); 160 | else 161 | toX[i]=x; 162 | if (!reverse) x += (width + spacing); 163 | 164 | maxDistanse=Math.max(fromX[i]-toX[i],maxDistanse); 165 | } 166 | if(maxDistanse==0){ 167 | setDuration(0); 168 | } 169 | } 170 | 171 | @Override 172 | protected void update(float percent) { 173 | for (int i = 0, n = children.size; i < n; i++) { 174 | Actor child = children.get(i); 175 | child.setX(toX[i]+(fromX[i]-toX[i])*(1-percent)); 176 | } 177 | } 178 | 179 | @Override 180 | protected void end() { 181 | super.end(); 182 | layout(); 183 | 184 | 185 | EventBusUtil.getDefaultEventBus().post(new PagerStage.UpdateRectEvent()); 186 | mChildChangeAction=null; 187 | } 188 | } 189 | 190 | public void layout () { 191 | float spacing = this.spacing, padBottom = this.padBottom; 192 | int align = this.align; 193 | boolean reverse = this.reverse, round = this.round; 194 | 195 | float groupHeight = getHeight() - padTop - padBottom; 196 | float x = !reverse ? padLeft : getWidth() - padRight + spacing; 197 | SnapshotArray children = getChildren(); 198 | for (int i = 0, n = children.size; i < n; i++) { 199 | Actor child = children.get(i); 200 | float width, height; 201 | if (child instanceof Layout) { 202 | Layout layout = (Layout)child; 203 | if (fill > 0) 204 | height = groupHeight * fill; 205 | else 206 | height = Math.min(layout.getPrefHeight(), groupHeight); 207 | height = Math.max(height, layout.getMinHeight()); 208 | float maxHeight = layout.getMaxHeight(); 209 | if (maxHeight > 0 && height > maxHeight) height = maxHeight; 210 | width = layout.getPrefWidth(); 211 | } else { 212 | width = child.getWidth(); 213 | height = child.getHeight(); 214 | if (fill > 0) height *= fill; 215 | } 216 | 217 | float y = padBottom; 218 | if ((align & Align.top) != 0) 219 | y += groupHeight - height; 220 | else if ((align & Align.bottom) == 0) // center 221 | y += (groupHeight - height) / 2; 222 | 223 | if (reverse) x -= (width + spacing); 224 | if (round) 225 | child.setBounds(Math.round(x), Math.round(y), Math.round(width), Math.round(height)); 226 | else 227 | child.setBounds(x, y, width, height); 228 | if (!reverse) x += (width + spacing); 229 | } 230 | } 231 | 232 | public float getPrefWidth () { 233 | if (sizeInvalid) computeSize(); 234 | return prefWidth; 235 | } 236 | 237 | public float getPrefHeight () { 238 | if (sizeInvalid) computeSize(); 239 | return prefHeight; 240 | } 241 | 242 | /** If true (the default), positions and sizes are rounded to integers. */ 243 | public void setRound (boolean round) { 244 | this.round = round; 245 | } 246 | 247 | /** The children will be ordered from right to left rather than the default left to right. */ 248 | public HorizontalGroup reverse () { 249 | reverse(true); 250 | return this; 251 | } 252 | 253 | /** If true, the children will be ordered from right to left rather than the default left to right. */ 254 | public HorizontalGroup reverse (boolean reverse) { 255 | this.reverse = reverse; 256 | return this; 257 | } 258 | 259 | public boolean getReverse () { 260 | return reverse; 261 | } 262 | 263 | /** Sets the space between children. */ 264 | public HorizontalGroup space (float spacing) { 265 | this.spacing = spacing; 266 | return this; 267 | } 268 | 269 | public float getSpace () { 270 | return spacing; 271 | } 272 | 273 | /** Sets the padTop, padLeft, padBottom, and padRight to the specified value. */ 274 | public HorizontalGroup pad (float pad) { 275 | padTop = pad; 276 | padLeft = pad; 277 | padBottom = pad; 278 | padRight = pad; 279 | return this; 280 | } 281 | 282 | public HorizontalGroup pad (float top, float left, float bottom, float right) { 283 | padTop = top; 284 | padLeft = left; 285 | padBottom = bottom; 286 | padRight = right; 287 | return this; 288 | } 289 | 290 | public HorizontalGroup padTop (float padTop) { 291 | this.padTop = padTop; 292 | return this; 293 | } 294 | 295 | public HorizontalGroup padLeft (float padLeft) { 296 | this.padLeft = padLeft; 297 | return this; 298 | } 299 | 300 | public HorizontalGroup padBottom (float padBottom) { 301 | this.padBottom = padBottom; 302 | return this; 303 | } 304 | 305 | public HorizontalGroup padRight (float padRight) { 306 | this.padRight = padRight; 307 | return this; 308 | } 309 | 310 | public float getPadTop () { 311 | return padTop; 312 | } 313 | 314 | public float getPadLeft () { 315 | return padLeft; 316 | } 317 | 318 | public float getPadBottom () { 319 | return padBottom; 320 | } 321 | 322 | public float getPadRight () { 323 | return padRight; 324 | } 325 | 326 | /** Sets the alignment of widgets within the horizontal group. Set to {@link com.badlogic.gdx.scenes.scene2d.utils.Align#center}, {@link com.badlogic.gdx.scenes.scene2d.utils.Align#top}, 327 | * {@link com.badlogic.gdx.scenes.scene2d.utils.Align#bottom}, {@link com.badlogic.gdx.scenes.scene2d.utils.Align#left}, {@link com.badlogic.gdx.scenes.scene2d.utils.Align#right}, or any combination of those. */ 328 | public HorizontalGroup align (int align) { 329 | this.align = align; 330 | return this; 331 | } 332 | 333 | /** Sets the alignment of widgets within the horizontal group to {@link com.badlogic.gdx.scenes.scene2d.utils.Align#center}. This clears any other alignment. */ 334 | public HorizontalGroup center () { 335 | align = Align.center; 336 | return this; 337 | } 338 | 339 | /** Sets {@link com.badlogic.gdx.scenes.scene2d.utils.Align#top} and clears {@link com.badlogic.gdx.scenes.scene2d.utils.Align#bottom} for the alignment of widgets within the horizontal group. */ 340 | public HorizontalGroup top () { 341 | align |= Align.top; 342 | align &= ~Align.bottom; 343 | return this; 344 | } 345 | 346 | /** Sets {@link com.badlogic.gdx.scenes.scene2d.utils.Align#bottom} and clears {@link com.badlogic.gdx.scenes.scene2d.utils.Align#top} for the alignment of widgets within the horizontal group. */ 347 | public HorizontalGroup bottom () { 348 | align |= Align.bottom; 349 | align &= ~Align.top; 350 | return this; 351 | } 352 | 353 | public int getAlign () { 354 | return align; 355 | } 356 | 357 | public HorizontalGroup fill () { 358 | fill = 1f; 359 | return this; 360 | } 361 | 362 | /** @param fill 0 will use pref width. */ 363 | public HorizontalGroup fill (float fill) { 364 | this.fill = fill; 365 | return this; 366 | } 367 | 368 | public float getFill () { 369 | return fill; 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/ui/ScrollPane.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.meizu.taskmanager.ui; 18 | 19 | import com.badlogic.gdx.Gdx; 20 | import com.badlogic.gdx.graphics.Color; 21 | import com.badlogic.gdx.graphics.g2d.Batch; 22 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 23 | import com.badlogic.gdx.math.Interpolation; 24 | import com.badlogic.gdx.math.MathUtils; 25 | import com.badlogic.gdx.math.Rectangle; 26 | import com.badlogic.gdx.math.Vector2; 27 | import com.badlogic.gdx.scenes.scene2d.Actor; 28 | import com.badlogic.gdx.scenes.scene2d.Event; 29 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 30 | import com.badlogic.gdx.scenes.scene2d.InputListener; 31 | import com.badlogic.gdx.scenes.scene2d.Stage; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 33 | import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; 34 | import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener; 35 | import com.badlogic.gdx.scenes.scene2d.utils.Cullable; 36 | import com.badlogic.gdx.scenes.scene2d.utils.Drawable; 37 | import com.badlogic.gdx.scenes.scene2d.utils.Layout; 38 | import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; 39 | 40 | /** A group that scrolls a child widget using scrollbars and/or mouse or touch dragging. 41 | *

42 | * The widget is sized to its preferred size. If the widget's preferred width or height is less than the size of this scroll pane, 43 | * it is set to the size of this scroll pane. Scrollbars appear when the widget is larger than the scroll pane. 44 | *

45 | * The scroll pane's preferred size is that of the child widget. At this size, the child widget will not need to scroll, so the 46 | * scroll pane is typically sized by ignoring the preferred size in one or both directions. 47 | * @author mzechner 48 | * @author Nathan Sweet */ 49 | public class ScrollPane extends WidgetGroup { 50 | private ScrollPaneStyle style; 51 | private Actor widget; 52 | 53 | final Rectangle hScrollBounds = new Rectangle(); 54 | final Rectangle vScrollBounds = new Rectangle(); 55 | final Rectangle hKnobBounds = new Rectangle(); 56 | final Rectangle vKnobBounds = new Rectangle(); 57 | private final Rectangle widgetAreaBounds = new Rectangle(); 58 | private final Rectangle widgetCullingArea = new Rectangle(); 59 | private final Rectangle scissorBounds = new Rectangle(); 60 | private ActorGestureListener flickScrollListener; 61 | 62 | boolean scrollX, scrollY; 63 | boolean vScrollOnRight = true; 64 | boolean hScrollOnBottom = true; 65 | float amountX, amountY; 66 | float visualAmountX, visualAmountY; 67 | float maxX, maxY; 68 | boolean touchScrollH, touchScrollV; 69 | final Vector2 lastPoint = new Vector2(); 70 | float areaWidth, areaHeight; 71 | private boolean fadeScrollBars = true, smoothScrolling = true; 72 | float fadeAlpha, fadeAlphaSeconds = 1, fadeDelay, fadeDelaySeconds = 1; 73 | boolean cancelTouchFocus = true; 74 | 75 | boolean flickScroll = true; 76 | float velocityX, velocityY; 77 | float flingTimer; 78 | private boolean overscrollX = true, overscrollY = true; 79 | float flingTime = 0.5f; 80 | private float overscrollDistance = 50, overscrollSpeedMin = 30, overscrollSpeedMax = 200; 81 | private boolean forceScrollX, forceScrollY; 82 | private boolean disableX, disableY; 83 | private boolean clamp = true; 84 | private boolean scrollbarsOnTop; 85 | private boolean variableSizeKnobs = true; 86 | int draggingPointer = -1; 87 | 88 | /** @param widget May be null. */ 89 | public ScrollPane (Actor widget) { 90 | this(widget, new ScrollPaneStyle()); 91 | } 92 | 93 | /** @param widget May be null. */ 94 | public ScrollPane (Actor widget, Skin skin) { 95 | this(widget, skin.get(ScrollPaneStyle.class)); 96 | } 97 | 98 | /** @param widget May be null. */ 99 | public ScrollPane (Actor widget, Skin skin, String styleName) { 100 | this(widget, skin.get(styleName, ScrollPaneStyle.class)); 101 | } 102 | 103 | /** @param widget May be null. */ 104 | public ScrollPane (Actor widget, ScrollPaneStyle style) { 105 | if (style == null) throw new IllegalArgumentException("style cannot be null."); 106 | this.style = style; 107 | setWidget(widget); 108 | setSize(150, 150); 109 | 110 | addCaptureListener(new InputListener() { 111 | private float handlePosition; 112 | 113 | public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { 114 | if (draggingPointer != -1) return false; 115 | if (pointer == 0 && button != 0) return false; 116 | getStage().setScrollFocus(ScrollPane.this); 117 | 118 | if (!flickScroll) resetFade(); 119 | 120 | if (fadeAlpha == 0) return false; 121 | 122 | if (scrollX && hScrollBounds.contains(x, y)) { 123 | event.stop(); 124 | resetFade(); 125 | if (hKnobBounds.contains(x, y)) { 126 | lastPoint.set(x, y); 127 | handlePosition = hKnobBounds.x; 128 | touchScrollH = true; 129 | draggingPointer = pointer; 130 | return true; 131 | } 132 | setScrollX(amountX + areaWidth * (x < hKnobBounds.x ? -1 : 1)); 133 | return true; 134 | } 135 | if (scrollY && vScrollBounds.contains(x, y)) { 136 | event.stop(); 137 | resetFade(); 138 | if (vKnobBounds.contains(x, y)) { 139 | lastPoint.set(x, y); 140 | handlePosition = vKnobBounds.y; 141 | touchScrollV = true; 142 | draggingPointer = pointer; 143 | return true; 144 | } 145 | setScrollY(amountY + areaHeight * (y < vKnobBounds.y ? 1 : -1)); 146 | return true; 147 | } 148 | return false; 149 | } 150 | 151 | public void touchUp (InputEvent event, float x, float y, int pointer, int button) { 152 | if (pointer != draggingPointer) return; 153 | cancel(); 154 | } 155 | 156 | public void touchDragged (InputEvent event, float x, float y, int pointer) { 157 | if (pointer != draggingPointer) return; 158 | if (touchScrollH) { 159 | float delta = x - lastPoint.x; 160 | float scrollH = handlePosition + delta; 161 | handlePosition = scrollH; 162 | scrollH = Math.max(hScrollBounds.x, scrollH); 163 | scrollH = Math.min(hScrollBounds.x + hScrollBounds.width - hKnobBounds.width, scrollH); 164 | float total = hScrollBounds.width - hKnobBounds.width; 165 | if (total != 0) setScrollPercentX((scrollH - hScrollBounds.x) / total); 166 | lastPoint.set(x, y); 167 | } else if (touchScrollV) { 168 | float delta = y - lastPoint.y; 169 | float scrollV = handlePosition + delta; 170 | handlePosition = scrollV; 171 | scrollV = Math.max(vScrollBounds.y, scrollV); 172 | scrollV = Math.min(vScrollBounds.y + vScrollBounds.height - vKnobBounds.height, scrollV); 173 | float total = vScrollBounds.height - vKnobBounds.height; 174 | if (total != 0) setScrollPercentY(1 - ((scrollV - vScrollBounds.y) / total)); 175 | lastPoint.set(x, y); 176 | } 177 | } 178 | 179 | public boolean mouseMoved (InputEvent event, float x, float y) { 180 | if (!flickScroll) resetFade(); 181 | return false; 182 | } 183 | }); 184 | 185 | flickScrollListener = new ActorGestureListener() { 186 | boolean canMove; 187 | public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) { 188 | if (!canMove && (forceScrollX || forceScrollY)) { 189 | if (forceScrollX) { 190 | if (Math.abs(deltaX) > Math.abs(deltaY)) { 191 | canMove = true; 192 | } else { 193 | return; 194 | } 195 | } else { 196 | if (Math.abs(deltaX) < Math.abs(deltaY)) { 197 | canMove = true; 198 | } else { 199 | return; 200 | } 201 | } 202 | } 203 | resetFade(); 204 | amountX -= deltaX; 205 | amountY += deltaY; 206 | clamp(); 207 | cancelTouchFocusedChild(event); 208 | } 209 | 210 | public void fling (InputEvent event, float x, float y, int button) { 211 | if (Math.abs(x) > 150) { 212 | flingTimer = flingTime; 213 | velocityX = x; 214 | cancelTouchFocusedChild(event); 215 | } 216 | if (Math.abs(y) > 150) { 217 | flingTimer = flingTime; 218 | velocityY = -y; 219 | cancelTouchFocusedChild(event); 220 | } 221 | } 222 | 223 | public boolean handle (Event event) { 224 | if (super.handle(event)) { 225 | if (((InputEvent)event).getType() == InputEvent.Type.touchDown) { 226 | flingTimer = 0; 227 | canMove=false; 228 | } 229 | return true; 230 | } 231 | return false; 232 | } 233 | }; 234 | addListener(flickScrollListener); 235 | 236 | addListener(new InputListener() { 237 | public boolean scrolled (InputEvent event, float x, float y, int amount) { 238 | resetFade(); 239 | if (scrollY) 240 | setScrollY(amountY + getMouseWheelY() * amount); 241 | else if (scrollX) // 242 | setScrollX(amountX + getMouseWheelX() * amount); 243 | else 244 | return false; 245 | return true; 246 | } 247 | }); 248 | } 249 | 250 | void resetFade () { 251 | fadeAlpha = fadeAlphaSeconds; 252 | fadeDelay = fadeDelaySeconds; 253 | } 254 | 255 | void cancelTouchFocusedChild (InputEvent event) { 256 | if (!cancelTouchFocus) return; 257 | Stage stage = getStage(); 258 | if (stage != null) stage.cancelTouchFocusExcept(flickScrollListener, this); 259 | } 260 | 261 | /** If currently scrolling by tracking a touch down, stop scrolling. */ 262 | public void cancel () { 263 | draggingPointer = -1; 264 | touchScrollH = false; 265 | touchScrollV = false; 266 | flickScrollListener.getGestureDetector().cancel(); 267 | } 268 | 269 | void clamp () { 270 | if (!clamp) return; 271 | scrollX(overscrollX ? MathUtils.clamp(amountX, -overscrollDistance, maxX + overscrollDistance) : MathUtils.clamp(amountX, 272 | 0, maxX)); 273 | scrollY(overscrollY ? MathUtils.clamp(amountY, -overscrollDistance, maxY + overscrollDistance) : MathUtils.clamp(amountY, 274 | 0, maxY)); 275 | } 276 | 277 | public void setStyle (ScrollPaneStyle style) { 278 | if (style == null) throw new IllegalArgumentException("style cannot be null."); 279 | this.style = style; 280 | invalidateHierarchy(); 281 | } 282 | 283 | /** Returns the scroll pane's style. Modifying the returned style may not have an effect until 284 | * {@link #setStyle(ScrollPane.ScrollPaneStyle)} is called. */ 285 | public ScrollPaneStyle getStyle () { 286 | return style; 287 | } 288 | 289 | public void act (float delta) { 290 | super.act(delta); 291 | 292 | boolean panning = flickScrollListener.getGestureDetector().isPanning(); 293 | boolean animating = false; 294 | 295 | if (fadeAlpha > 0 && fadeScrollBars && !panning && !touchScrollH && !touchScrollV) { 296 | fadeDelay -= delta; 297 | if (fadeDelay <= 0) fadeAlpha = Math.max(0, fadeAlpha - delta); 298 | animating = true; 299 | } 300 | 301 | if (flingTimer > 0) { 302 | resetFade(); 303 | 304 | float alpha = flingTimer / flingTime; 305 | amountX -= velocityX * alpha * delta; 306 | amountY -= velocityY * alpha * delta; 307 | clamp(); 308 | 309 | // Stop fling if hit overscroll distance. 310 | if (amountX == -overscrollDistance) velocityX = 0; 311 | if (amountX >= maxX + overscrollDistance) velocityX = 0; 312 | if (amountY == -overscrollDistance) velocityY = 0; 313 | if (amountY >= maxY + overscrollDistance) velocityY = 0; 314 | 315 | flingTimer -= delta; 316 | if (flingTimer <= 0) { 317 | velocityX = 0; 318 | velocityY = 0; 319 | } 320 | 321 | animating = true; 322 | } 323 | 324 | if (smoothScrolling && flingTimer <= 0 && !touchScrollH && !touchScrollV && !panning) { 325 | if (visualAmountX != amountX) { 326 | if (visualAmountX < amountX) 327 | visualScrollX(Math.min(amountX, visualAmountX + Math.max(200 * delta, (amountX - visualAmountX) * 7 * delta))); 328 | else 329 | visualScrollX(Math.max(amountX, visualAmountX - Math.max(200 * delta, (visualAmountX - amountX) * 7 * delta))); 330 | animating = true; 331 | } 332 | if (visualAmountY != amountY) { 333 | if (visualAmountY < amountY) 334 | visualScrollY(Math.min(amountY, visualAmountY + Math.max(200 * delta, (amountY - visualAmountY) * 7 * delta))); 335 | else 336 | visualScrollY(Math.max(amountY, visualAmountY - Math.max(200 * delta, (visualAmountY - amountY) * 7 * delta))); 337 | animating = true; 338 | } 339 | } else { 340 | if (visualAmountX != amountX) visualScrollX(amountX); 341 | if (visualAmountY != amountY) visualScrollY(amountY); 342 | } 343 | 344 | if (!panning) { 345 | if (overscrollX && scrollX) { 346 | if (amountX < 0) { 347 | resetFade(); 348 | amountX += (overscrollSpeedMin + (overscrollSpeedMax - overscrollSpeedMin) * -amountX / overscrollDistance) 349 | * delta; 350 | if (amountX > 0) scrollX(0); 351 | animating = true; 352 | } else if (amountX > maxX) { 353 | resetFade(); 354 | amountX -= (overscrollSpeedMin + (overscrollSpeedMax - overscrollSpeedMin) * -(maxX - amountX) 355 | / overscrollDistance) 356 | * delta; 357 | if (amountX < maxX) scrollX(maxX); 358 | animating = true; 359 | } 360 | } 361 | if (overscrollY && scrollY) { 362 | if (amountY < 0) { 363 | resetFade(); 364 | amountY += (overscrollSpeedMin + (overscrollSpeedMax - overscrollSpeedMin) * -amountY / overscrollDistance) 365 | * delta; 366 | if (amountY > 0) scrollY(0); 367 | animating = true; 368 | } else if (amountY > maxY) { 369 | resetFade(); 370 | amountY -= (overscrollSpeedMin + (overscrollSpeedMax - overscrollSpeedMin) * -(maxY - amountY) 371 | / overscrollDistance) 372 | * delta; 373 | if (amountY < maxY) scrollY(maxY); 374 | animating = true; 375 | } 376 | } 377 | } 378 | 379 | if (animating) { 380 | Stage stage = getStage(); 381 | if (stage != null && stage.getActionsRequestRendering()) Gdx.graphics.requestRendering(); 382 | } 383 | } 384 | 385 | public void layout () { 386 | final Drawable bg = style.background; 387 | final Drawable hScrollKnob = style.hScrollKnob; 388 | final Drawable vScrollKnob = style.vScrollKnob; 389 | 390 | float bgLeftWidth = 0, bgRightWidth = 0, bgTopHeight = 0, bgBottomHeight = 0; 391 | if (bg != null) { 392 | bgLeftWidth = bg.getLeftWidth(); 393 | bgRightWidth = bg.getRightWidth(); 394 | bgTopHeight = bg.getTopHeight(); 395 | bgBottomHeight = bg.getBottomHeight(); 396 | } 397 | 398 | float width = getWidth(); 399 | float height = getHeight(); 400 | 401 | float scrollbarHeight = 0; 402 | if (hScrollKnob != null) scrollbarHeight = hScrollKnob.getMinHeight(); 403 | if (style.hScroll != null) scrollbarHeight = Math.max(scrollbarHeight, style.hScroll.getMinHeight()); 404 | float scrollbarWidth = 0; 405 | if (vScrollKnob != null) scrollbarWidth = vScrollKnob.getMinWidth(); 406 | if (style.vScroll != null) scrollbarWidth = Math.max(scrollbarWidth, style.vScroll.getMinWidth()); 407 | 408 | // Get available space size by subtracting background's padded area. 409 | areaWidth = width - bgLeftWidth - bgRightWidth; 410 | areaHeight = height - bgTopHeight - bgBottomHeight; 411 | 412 | if (widget == null) return; 413 | 414 | // Get widget's desired width. 415 | float widgetWidth, widgetHeight; 416 | if (widget instanceof Layout) { 417 | Layout layout = (Layout)widget; 418 | widgetWidth = layout.getPrefWidth(); 419 | widgetHeight = layout.getPrefHeight(); 420 | } else { 421 | widgetWidth = widget.getWidth(); 422 | widgetHeight = widget.getHeight(); 423 | } 424 | 425 | // Determine if horizontal/vertical scrollbars are needed. 426 | scrollX = forceScrollX || (widgetWidth > areaWidth && !disableX); 427 | scrollY = forceScrollY || (widgetHeight > areaHeight && !disableY); 428 | 429 | boolean fade = fadeScrollBars; 430 | if (!fade) { 431 | // Check again, now taking into account the area that's taken up by any enabled scrollbars. 432 | if (scrollY) { 433 | areaWidth -= scrollbarWidth; 434 | if (!scrollX && widgetWidth > areaWidth && !disableX) scrollX = true; 435 | } 436 | if (scrollX) { 437 | areaHeight -= scrollbarHeight; 438 | if (!scrollY && widgetHeight > areaHeight && !disableY) { 439 | scrollY = true; 440 | areaWidth -= scrollbarWidth; 441 | } 442 | } 443 | } 444 | 445 | // The bounds of the scrollable area for the widget. 446 | widgetAreaBounds.set(bgLeftWidth, bgBottomHeight, areaWidth, areaHeight); 447 | 448 | if (fade) { 449 | // Make sure widget is drawn under fading scrollbars. 450 | if (scrollX && scrollY) { 451 | areaHeight -= scrollbarHeight; 452 | areaWidth -= scrollbarWidth; 453 | } 454 | } else { 455 | if (scrollbarsOnTop) { 456 | // Make sure widget is drawn under non-fading scrollbars. 457 | if (scrollX) widgetAreaBounds.height += scrollbarHeight; 458 | if (scrollY) widgetAreaBounds.width += scrollbarWidth; 459 | } else { 460 | // Offset widget area y for horizontal scrollbar at bottom. 461 | if (scrollX && hScrollOnBottom) widgetAreaBounds.y += scrollbarHeight; 462 | // Offset widget area x for vertical scrollbar at left. 463 | if (scrollY && !vScrollOnRight) widgetAreaBounds.x += scrollbarWidth; 464 | } 465 | } 466 | 467 | // If the widget is smaller than the available space, make it take up the available space. 468 | widgetWidth = disableX ? areaWidth : Math.max(areaWidth, widgetWidth); 469 | widgetHeight = disableY ? areaHeight : Math.max(areaHeight, widgetHeight); 470 | 471 | maxX = widgetWidth - areaWidth; 472 | maxY = widgetHeight - areaHeight; 473 | if (fade) { 474 | // Make sure widget is drawn under fading scrollbars. 475 | if (scrollX) maxY -= scrollbarHeight; 476 | if (scrollY) maxX -= scrollbarWidth; 477 | } 478 | scrollX(MathUtils.clamp(amountX, 0, maxX)); 479 | scrollY(MathUtils.clamp(amountY, 0, maxY)); 480 | 481 | // Set the bounds and scroll knob sizes if scrollbars are needed. 482 | if (scrollX) { 483 | if (hScrollKnob != null) { 484 | float hScrollHeight = style.hScroll != null ? style.hScroll.getMinHeight() : hScrollKnob.getMinHeight(); 485 | // The corner gap where the two scroll bars intersect might have to flip from right to left. 486 | float boundsX = vScrollOnRight ? bgLeftWidth : bgLeftWidth + scrollbarWidth; 487 | // Scrollbar on the top or bottom. 488 | float boundsY = hScrollOnBottom ? bgBottomHeight : height - bgTopHeight - hScrollHeight; 489 | hScrollBounds.set(boundsX, boundsY, areaWidth, hScrollHeight); 490 | if (variableSizeKnobs) 491 | hKnobBounds.width = Math.max(hScrollKnob.getMinWidth(), (int)(hScrollBounds.width * areaWidth / widgetWidth)); 492 | else 493 | hKnobBounds.width = hScrollKnob.getMinWidth(); 494 | 495 | hKnobBounds.height = hScrollKnob.getMinHeight(); 496 | 497 | hKnobBounds.x = hScrollBounds.x + (int)((hScrollBounds.width - hKnobBounds.width) * getScrollPercentX()); 498 | hKnobBounds.y = hScrollBounds.y; 499 | } else { 500 | hScrollBounds.set(0, 0, 0, 0); 501 | hKnobBounds.set(0, 0, 0, 0); 502 | } 503 | } 504 | if (scrollY) { 505 | if (vScrollKnob != null) { 506 | float vScrollWidth = style.vScroll != null ? style.vScroll.getMinWidth() : vScrollKnob.getMinWidth(); 507 | // the small gap where the two scroll bars intersect might have to flip from bottom to top 508 | float boundsX, boundsY; 509 | if (hScrollOnBottom) { 510 | boundsY = height - bgTopHeight - areaHeight; 511 | } else { 512 | boundsY = bgBottomHeight; 513 | } 514 | // bar on the left or right 515 | if (vScrollOnRight) { 516 | boundsX = width - bgRightWidth - vScrollWidth; 517 | } else { 518 | boundsX = bgLeftWidth; 519 | } 520 | vScrollBounds.set(boundsX, boundsY, vScrollWidth, areaHeight); 521 | vKnobBounds.width = vScrollKnob.getMinWidth(); 522 | if (variableSizeKnobs) 523 | vKnobBounds.height = Math.max(vScrollKnob.getMinHeight(), (int)(vScrollBounds.height * areaHeight / widgetHeight)); 524 | else 525 | vKnobBounds.height = vScrollKnob.getMinHeight(); 526 | 527 | if (vScrollOnRight) { 528 | vKnobBounds.x = width - bgRightWidth - vScrollKnob.getMinWidth(); 529 | } else { 530 | vKnobBounds.x = bgLeftWidth; 531 | } 532 | vKnobBounds.y = vScrollBounds.y + (int)((vScrollBounds.height - vKnobBounds.height) * (1 - getScrollPercentY())); 533 | } else { 534 | vScrollBounds.set(0, 0, 0, 0); 535 | vKnobBounds.set(0, 0, 0, 0); 536 | } 537 | } 538 | 539 | widget.setSize(widgetWidth, widgetHeight); 540 | if (widget instanceof Layout) ((Layout)widget).validate(); 541 | } 542 | 543 | @Override 544 | public void draw (Batch batch, float parentAlpha) { 545 | if (widget == null) return; 546 | 547 | validate(); 548 | 549 | // Setup transform for this group. 550 | applyTransform(batch, computeTransform()); 551 | 552 | if (scrollX) 553 | hKnobBounds.x = hScrollBounds.x + (int)((hScrollBounds.width - hKnobBounds.width) * getVisualScrollPercentX()); 554 | if (scrollY) 555 | vKnobBounds.y = vScrollBounds.y + (int)((vScrollBounds.height - vKnobBounds.height) * (1 - getVisualScrollPercentY())); 556 | 557 | // Calculate the widget's position depending on the scroll state and available widget area. 558 | float y = widgetAreaBounds.y; 559 | if (!scrollY) 560 | y -= (int)maxY; 561 | else 562 | y -= (int)(maxY - visualAmountY); 563 | 564 | float x = widgetAreaBounds.x; 565 | if (scrollX) x -= (int)visualAmountX; 566 | 567 | if (!fadeScrollBars && scrollbarsOnTop) { 568 | if (scrollX && hScrollOnBottom) { 569 | float scrollbarHeight = 0; 570 | if (style.hScrollKnob != null) scrollbarHeight = style.hScrollKnob.getMinHeight(); 571 | if (style.hScroll != null) scrollbarHeight = Math.max(scrollbarHeight, style.hScroll.getMinHeight()); 572 | y += scrollbarHeight; 573 | } 574 | if (scrollY && !vScrollOnRight) { 575 | float scrollbarWidth = 0; 576 | if (style.hScrollKnob != null) scrollbarWidth = style.hScrollKnob.getMinWidth(); 577 | if (style.hScroll != null) scrollbarWidth = Math.max(scrollbarWidth, style.hScroll.getMinWidth()); 578 | x += scrollbarWidth; 579 | } 580 | } 581 | 582 | widget.setPosition(x, y); 583 | 584 | if (widget instanceof Cullable) { 585 | widgetCullingArea.x = -widget.getX() + widgetAreaBounds.x; 586 | widgetCullingArea.y = -widget.getY() + widgetAreaBounds.y; 587 | widgetCullingArea.width = widgetAreaBounds.width; 588 | widgetCullingArea.height = widgetAreaBounds.height; 589 | ((Cullable)widget).setCullingArea(widgetCullingArea); 590 | } 591 | 592 | // Draw the background ninepatch. 593 | Color color = getColor(); 594 | batch.setColor(color.r, color.g, color.b, color.a * parentAlpha); 595 | if (style.background != null) { 596 | style.background.draw(batch, 0, 0, getWidth(), getHeight()); 597 | batch.flush(); 598 | } 599 | 600 | // Caculate the scissor bounds based on the batch transform, the available widget area and the camera transform. We need to 601 | // project those to screen coordinates for OpenGL ES to consume. 602 | getStage().calculateScissors(widgetAreaBounds, scissorBounds); 603 | 604 | // Enable scissors for widget area and draw the widget. 605 | if (ScissorStack.pushScissors(scissorBounds)) { 606 | drawChildren(batch, parentAlpha); 607 | batch.flush(); 608 | ScissorStack.popScissors(); 609 | } 610 | 611 | // Render scrollbars and knobs on top. 612 | batch.setColor(color.r, color.g, color.b, color.a * parentAlpha * Interpolation.fade.apply(fadeAlpha / fadeAlphaSeconds)); 613 | if (scrollX && scrollY) { 614 | if (style.corner != null) { 615 | style.corner 616 | .draw(batch, hScrollBounds.x + hScrollBounds.width, hScrollBounds.y, vScrollBounds.width, vScrollBounds.y); 617 | } 618 | } 619 | if (scrollX) { 620 | if (style.hScroll != null) 621 | style.hScroll.draw(batch, hScrollBounds.x, hScrollBounds.y, hScrollBounds.width, hScrollBounds.height); 622 | if (style.hScrollKnob != null) 623 | style.hScrollKnob.draw(batch, hKnobBounds.x, hKnobBounds.y, hKnobBounds.width, hKnobBounds.height); 624 | } 625 | if (scrollY) { 626 | if (style.vScroll != null) 627 | style.vScroll.draw(batch, vScrollBounds.x, vScrollBounds.y, vScrollBounds.width, vScrollBounds.height); 628 | if (style.vScrollKnob != null) 629 | style.vScrollKnob.draw(batch, vKnobBounds.x, vKnobBounds.y, vKnobBounds.width, vKnobBounds.height); 630 | } 631 | 632 | resetTransform(batch); 633 | } 634 | 635 | /** Generate fling gesture. 636 | * @param flingTime Time in seconds for which you want to fling last. 637 | * @param velocityX Velocity for horizontal direction. 638 | * @param velocityY Velocity for vertical direction. */ 639 | public void fling (float flingTime, float velocityX, float velocityY) { 640 | this.flingTimer = flingTime; 641 | this.velocityX = velocityX; 642 | this.velocityY = velocityY; 643 | } 644 | 645 | public float getPrefWidth () { 646 | if (widget instanceof Layout) { 647 | float width = ((Layout)widget).getPrefWidth(); 648 | if (style.background != null) width += style.background.getLeftWidth() + style.background.getRightWidth(); 649 | if (forceScrollY) { 650 | float scrollbarWidth = 0; 651 | if (style.vScrollKnob != null) scrollbarWidth = style.vScrollKnob.getMinWidth(); 652 | if (style.vScroll != null) scrollbarWidth = Math.max(scrollbarWidth, style.vScroll.getMinWidth()); 653 | width += scrollbarWidth; 654 | } 655 | return width; 656 | } 657 | return 150; 658 | } 659 | 660 | public float getPrefHeight () { 661 | if (widget instanceof Layout) { 662 | float height = ((Layout)widget).getPrefHeight(); 663 | if (style.background != null) height += style.background.getTopHeight() + style.background.getBottomHeight(); 664 | if (forceScrollX) { 665 | float scrollbarHeight = 0; 666 | if (style.hScrollKnob != null) scrollbarHeight = style.hScrollKnob.getMinHeight(); 667 | if (style.hScroll != null) scrollbarHeight = Math.max(scrollbarHeight, style.hScroll.getMinHeight()); 668 | height += scrollbarHeight; 669 | } 670 | return height; 671 | } 672 | return 150; 673 | } 674 | 675 | public float getMinWidth () { 676 | return 0; 677 | } 678 | 679 | public float getMinHeight () { 680 | return 0; 681 | } 682 | 683 | /** Sets the {@link com.badlogic.gdx.scenes.scene2d.Actor} embedded in this scroll pane. 684 | * @param widget May be null to remove any current actor. */ 685 | public void setWidget (Actor widget) { 686 | if (widget == this) throw new IllegalArgumentException("widget cannot be the ScrollPane."); 687 | if (this.widget != null) super.removeActor(this.widget); 688 | this.widget = widget; 689 | if (widget != null) super.addActor(widget); 690 | } 691 | 692 | /** Returns the actor embedded in this scroll pane, or null. */ 693 | public Actor getWidget () { 694 | return widget; 695 | } 696 | 697 | /** @deprecated ScrollPane may have only a single child. 698 | * @see #setWidget(com.badlogic.gdx.scenes.scene2d.Actor) */ 699 | public void addActor (Actor actor) { 700 | throw new UnsupportedOperationException("Use ScrollPane#setWidget."); 701 | } 702 | 703 | /** @deprecated ScrollPane may have only a single child. 704 | * @see #setWidget(com.badlogic.gdx.scenes.scene2d.Actor) */ 705 | public void addActorAt (int index, Actor actor) { 706 | throw new UnsupportedOperationException("Use ScrollPane#setWidget."); 707 | } 708 | 709 | /** @deprecated ScrollPane may have only a single child. 710 | * @see #setWidget(com.badlogic.gdx.scenes.scene2d.Actor) */ 711 | public void addActorBefore (Actor actorBefore, Actor actor) { 712 | throw new UnsupportedOperationException("Use ScrollPane#setWidget."); 713 | } 714 | 715 | /** @deprecated ScrollPane may have only a single child. 716 | * @see #setWidget(com.badlogic.gdx.scenes.scene2d.Actor) */ 717 | public void addActorAfter (Actor actorAfter, Actor actor) { 718 | throw new UnsupportedOperationException("Use ScrollPane#setWidget."); 719 | } 720 | 721 | public boolean removeActor (Actor actor) { 722 | if (actor != widget) return false; 723 | setWidget(null); 724 | return true; 725 | } 726 | 727 | public Actor hit (float x, float y, boolean touchable) { 728 | if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) return null; 729 | if (scrollX && hScrollBounds.contains(x, y)) return this; 730 | if (scrollY && vScrollBounds.contains(x, y)) return this; 731 | return super.hit(x, y, touchable); 732 | } 733 | 734 | /** Called whenever the x scroll amount is changed. */ 735 | protected void scrollX (float pixelsX) { 736 | this.amountX = pixelsX; 737 | } 738 | 739 | /** Called whenever the y scroll amount is changed. */ 740 | protected void scrollY (float pixelsY) { 741 | this.amountY = pixelsY; 742 | } 743 | 744 | /** Called whenever the visual x scroll amount is changed. */ 745 | protected void visualScrollX (float pixelsX) { 746 | this.visualAmountX = pixelsX; 747 | } 748 | 749 | /** Called whenever the visual y scroll amount is changed. */ 750 | protected void visualScrollY (float pixelsY) { 751 | this.visualAmountY = pixelsY; 752 | } 753 | 754 | /** Returns the amount to scroll horizontally when the mouse wheel is scrolled. */ 755 | protected float getMouseWheelX () { 756 | return Math.max(areaWidth * 0.9f, maxX * 0.1f) / 4; 757 | } 758 | 759 | /** Returns the amount to scroll vertically when the mouse wheel is scrolled. */ 760 | protected float getMouseWheelY () { 761 | return Math.max(areaHeight * 0.9f, maxY * 0.1f) / 4; 762 | } 763 | 764 | public void setScrollX (float pixels) { 765 | scrollX(MathUtils.clamp(pixels, 0, maxX)); 766 | } 767 | 768 | /** Returns the x scroll position in pixels, where 0 is the left of the scroll pane. */ 769 | public float getScrollX () { 770 | return amountX; 771 | } 772 | 773 | public void setScrollY (float pixels) { 774 | scrollY(MathUtils.clamp(pixels, 0, maxY)); 775 | } 776 | 777 | /** Returns the y scroll position in pixels, where 0 is the top of the scroll pane. */ 778 | public float getScrollY () { 779 | return amountY; 780 | } 781 | 782 | /** Sets the visual scroll amount equal to the scroll amount. This can be used when setting the scroll amount without animating. */ 783 | public void updateVisualScroll () { 784 | visualAmountX = amountX; 785 | visualAmountY = amountY; 786 | } 787 | 788 | public float getVisualScrollX () { 789 | return !scrollX ? 0 : visualAmountX; 790 | } 791 | 792 | public float getVisualScrollY () { 793 | return !scrollY ? 0 : visualAmountY; 794 | } 795 | 796 | public float getVisualScrollPercentX () { 797 | return MathUtils.clamp(visualAmountX / maxX, 0, 1); 798 | } 799 | 800 | public float getVisualScrollPercentY () { 801 | return MathUtils.clamp(visualAmountY / maxY, 0, 1); 802 | } 803 | 804 | public float getScrollPercentX () { 805 | return MathUtils.clamp(amountX / maxX, 0, 1); 806 | } 807 | 808 | public void setScrollPercentX (float percentX) { 809 | scrollX(maxX * MathUtils.clamp(percentX, 0, 1)); 810 | } 811 | 812 | public float getScrollPercentY () { 813 | return MathUtils.clamp(amountY / maxY, 0, 1); 814 | } 815 | 816 | public void setScrollPercentY (float percentY) { 817 | scrollY(maxY * MathUtils.clamp(percentY, 0, 1)); 818 | } 819 | 820 | public void setFlickScroll (boolean flickScroll) { 821 | if (this.flickScroll == flickScroll) return; 822 | this.flickScroll = flickScroll; 823 | if (flickScroll) 824 | addListener(flickScrollListener); 825 | else 826 | removeListener(flickScrollListener); 827 | invalidate(); 828 | } 829 | 830 | public void setFlickScrollTapSquareSize (float halfTapSquareSize) { 831 | flickScrollListener.getGestureDetector().setTapSquareSize(halfTapSquareSize); 832 | } 833 | 834 | /** Sets the scroll offset so the specified rectangle is fully in view, if possible. Coordinates are in the scroll pane widget's 835 | * coordinate system. */ 836 | public void scrollTo (float x, float y, float width, float height) { 837 | scrollTo(x, y, width, height, false, false); 838 | } 839 | 840 | /** Sets the scroll offset so the specified rectangle is fully in view, and optionally centered vertically and/or horizontally, 841 | * if possible. Coordinates are in the scroll pane widget's coordinate system. */ 842 | public void scrollTo (float x, float y, float width, float height, boolean centerHorizontal, boolean centerVertical) { 843 | float amountX = this.amountX; 844 | if (centerHorizontal) { 845 | amountX = x - areaWidth / 2 + width / 2; 846 | } else { 847 | if (x + width > amountX + areaWidth) amountX = x + width - areaWidth; 848 | if (x < amountX) amountX = x; 849 | } 850 | scrollX(MathUtils.clamp(amountX, 0, maxX)); 851 | 852 | float amountY = this.amountY; 853 | if (centerVertical) { 854 | amountY = maxY - y + areaHeight / 2 - height / 2; 855 | } else { 856 | if (amountY > maxY - y - height + areaHeight) amountY = maxY - y - height + areaHeight; 857 | if (amountY < maxY - y) amountY = maxY - y; 858 | } 859 | scrollY(MathUtils.clamp(amountY, 0, maxY)); 860 | } 861 | 862 | /** Returns the maximum scroll value in the x direction. */ 863 | public float getMaxX () { 864 | return maxX; 865 | } 866 | 867 | /** Returns the maximum scroll value in the y direction. */ 868 | public float getMaxY () { 869 | return maxY; 870 | } 871 | 872 | public float getScrollBarHeight () { 873 | if (!scrollX) return 0; 874 | float height = 0; 875 | if (style.hScrollKnob != null) height = style.hScrollKnob.getMinHeight(); 876 | if (style.hScroll != null) height = Math.max(height, style.hScroll.getMinHeight()); 877 | return height; 878 | } 879 | 880 | public float getScrollBarWidth () { 881 | if (!scrollY) return 0; 882 | float width = 0; 883 | if (style.vScrollKnob != null) width = style.vScrollKnob.getMinWidth(); 884 | if (style.vScroll != null) width = Math.max(width, style.vScroll.getMinWidth()); 885 | return width; 886 | } 887 | 888 | /** Returns the width of the scrolled viewport. */ 889 | public float getScrollWidth () { 890 | return areaWidth; 891 | } 892 | 893 | /** Returns the height of the scrolled viewport. */ 894 | public float getScrollHeight () { 895 | return areaHeight; 896 | } 897 | 898 | /** Returns true if the widget is larger than the scroll pane horizontally. */ 899 | public boolean isScrollX () { 900 | return scrollX; 901 | } 902 | 903 | /** Returns true if the widget is larger than the scroll pane vertically. */ 904 | public boolean isScrollY () { 905 | return scrollY; 906 | } 907 | 908 | /** Disables scrolling in a direction. The widget will be sized to the FlickScrollPane in the disabled direction. */ 909 | public void setScrollingDisabled (boolean x, boolean y) { 910 | disableX = x; 911 | disableY = y; 912 | } 913 | 914 | public boolean isLeftEdge () { 915 | return !scrollX || amountX <= 0; 916 | } 917 | 918 | public boolean isRightEdge () { 919 | return !scrollX || amountX >= maxX; 920 | } 921 | 922 | public boolean isTopEdge () { 923 | return !scrollY || amountY <= 0; 924 | } 925 | 926 | public boolean isBottomEdge () { 927 | return !scrollY || amountY >= maxY; 928 | } 929 | 930 | public boolean isDragging () { 931 | return draggingPointer != -1; 932 | } 933 | 934 | public boolean isPanning () { 935 | return flickScrollListener.getGestureDetector().isPanning(); 936 | } 937 | 938 | public boolean isFlinging () { 939 | return flingTimer > 0; 940 | } 941 | 942 | public void setVelocityX (float velocityX) { 943 | this.velocityX = velocityX; 944 | } 945 | 946 | /** Gets the flick scroll y velocity. */ 947 | public float getVelocityX () { 948 | if (flingTimer <= 0) return 0; 949 | float alpha = flingTimer / flingTime; 950 | alpha = alpha * alpha * alpha; 951 | return velocityX * alpha * alpha * alpha; 952 | } 953 | 954 | public void setVelocityY (float velocityY) { 955 | this.velocityY = velocityY; 956 | } 957 | 958 | /** Gets the flick scroll y velocity. */ 959 | public float getVelocityY () { 960 | return velocityY; 961 | } 962 | 963 | /** For flick scroll, if true the widget can be scrolled slightly past its bounds and will animate back to its bounds when 964 | * scrolling is stopped. Default is true. */ 965 | public void setOverscroll (boolean overscrollX, boolean overscrollY) { 966 | this.overscrollX = overscrollX; 967 | this.overscrollY = overscrollY; 968 | } 969 | 970 | /** For flick scroll, sets the overscroll distance in pixels and the speed it returns to the widget's bounds in seconds. Default 971 | * is 50, 30, 200. */ 972 | public void setupOverscroll (float distance, float speedMin, float speedMax) { 973 | overscrollDistance = distance; 974 | overscrollSpeedMin = speedMin; 975 | overscrollSpeedMax = speedMax; 976 | } 977 | 978 | /** Forces enabling scrollbars (for non-flick scroll) and overscrolling (for flick scroll) in a direction, even if the contents 979 | * do not exceed the bounds in that direction. */ 980 | public void setForceScroll (boolean x, boolean y) { 981 | forceScrollX = x; 982 | forceScrollY = y; 983 | } 984 | 985 | public boolean isForceScrollX () { 986 | return forceScrollX; 987 | } 988 | 989 | public boolean isForceScrollY () { 990 | return forceScrollY; 991 | } 992 | 993 | /** For flick scroll, sets the amount of time in seconds that a fling will continue to scroll. Default is 1. */ 994 | public void setFlingTime (float flingTime) { 995 | this.flingTime = flingTime; 996 | } 997 | 998 | /** For flick scroll, prevents scrolling out of the widget's bounds. Default is true. */ 999 | public void setClamp (boolean clamp) { 1000 | this.clamp = clamp; 1001 | } 1002 | 1003 | /** Set the position of the vertical and horizontal scroll bars. */ 1004 | public void setScrollBarPositions (boolean bottom, boolean right) { 1005 | hScrollOnBottom = bottom; 1006 | vScrollOnRight = right; 1007 | } 1008 | 1009 | /** When true the scrollbars don't reduce the scrollable size and fade out after some time of not being used. */ 1010 | public void setFadeScrollBars (boolean fadeScrollBars) { 1011 | if (this.fadeScrollBars == fadeScrollBars) return; 1012 | this.fadeScrollBars = fadeScrollBars; 1013 | if (!fadeScrollBars) fadeAlpha = fadeAlphaSeconds; 1014 | invalidate(); 1015 | } 1016 | 1017 | public void setupFadeScrollBars (float fadeAlphaSeconds, float fadeDelaySeconds) { 1018 | this.fadeAlphaSeconds = fadeAlphaSeconds; 1019 | this.fadeDelaySeconds = fadeDelaySeconds; 1020 | } 1021 | 1022 | public void setSmoothScrolling (boolean smoothScrolling) { 1023 | this.smoothScrolling = smoothScrolling; 1024 | } 1025 | 1026 | /** When false (the default), the widget is clipped so it is not drawn under the scrollbars. When true, the widget is clipped to 1027 | * the entire scroll pane bounds and the scrollbars are drawn on top of the widget. If {@link #setFadeScrollBars(boolean)} is 1028 | * true, the scroll bars are always drawn on top. */ 1029 | public void setScrollbarsOnTop (boolean scrollbarsOnTop) { 1030 | this.scrollbarsOnTop = scrollbarsOnTop; 1031 | invalidate(); 1032 | } 1033 | 1034 | public boolean getVariableSizeKnobs () { 1035 | return variableSizeKnobs; 1036 | } 1037 | 1038 | /** If true, the scroll knobs are sized based on {@link #getMaxX()} or {@link #getMaxY()}. If false, the scroll knobs are sized 1039 | * based on {@link com.badlogic.gdx.scenes.scene2d.utils.Drawable#getMinWidth()} or {@link com.badlogic.gdx.scenes.scene2d.utils.Drawable#getMinHeight()}. Default is true. */ 1040 | public void setVariableSizeKnobs (boolean variableSizeKnobs) { 1041 | this.variableSizeKnobs = variableSizeKnobs; 1042 | } 1043 | 1044 | /** When true (default), the {@link com.badlogic.gdx.scenes.scene2d.Stage#cancelTouchFocus()} touch focus} is cancelled when flick scrolling begins. This causes 1045 | * widgets inside the scrollpane that have received touchDown to receive touchUp when flick scrolling begins. */ 1046 | public void setCancelTouchFocus (boolean cancelTouchFocus) { 1047 | this.cancelTouchFocus = cancelTouchFocus; 1048 | } 1049 | 1050 | public void drawDebug (ShapeRenderer shapes) { 1051 | shapes.flush(); 1052 | applyTransform(shapes, computeTransform()); 1053 | if (ScissorStack.pushScissors(scissorBounds)) { 1054 | drawDebugChildren(shapes); 1055 | ScissorStack.popScissors(); 1056 | } 1057 | resetTransform(shapes); 1058 | } 1059 | 1060 | public String toString () { 1061 | if (widget == null) 1062 | return super.toString(); 1063 | else 1064 | return super.toString() + ": " + widget.toString(); 1065 | } 1066 | 1067 | /** The style for a scroll pane, see {@link ScrollPane}. 1068 | * @author mzechner 1069 | * @author Nathan Sweet */ 1070 | static public class ScrollPaneStyle { 1071 | /** Optional. */ 1072 | public Drawable background, corner; 1073 | /** Optional. */ 1074 | public Drawable hScroll, hScrollKnob; 1075 | /** Optional. */ 1076 | public Drawable vScroll, vScrollKnob; 1077 | 1078 | public ScrollPaneStyle () { 1079 | } 1080 | 1081 | public ScrollPaneStyle (Drawable background, Drawable hScroll, Drawable hScrollKnob, Drawable vScroll, Drawable vScrollKnob) { 1082 | this.background = background; 1083 | this.hScroll = hScroll; 1084 | this.hScrollKnob = hScrollKnob; 1085 | this.vScroll = vScroll; 1086 | this.vScrollKnob = vScrollKnob; 1087 | } 1088 | 1089 | public ScrollPaneStyle (ScrollPaneStyle style) { 1090 | this.background = style.background; 1091 | this.hScroll = style.hScroll; 1092 | this.hScrollKnob = style.hScrollKnob; 1093 | this.vScroll = style.vScroll; 1094 | this.vScrollKnob = style.vScrollKnob; 1095 | } 1096 | } 1097 | } 1098 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/utils/action/CancelableAction.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.utils.action; 2 | 3 | public interface CancelableAction { 4 | public void cancel(); 5 | } 6 | -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/utils/animation/FloatEvaluator.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.utils.animation; 2 | 3 | public class FloatEvaluator implements TypeEvaluator { 4 | public Float evaluate(float fraction, Number startValue, Number endValue) { 5 | float startFloat = startValue.floatValue(); 6 | return startFloat + fraction * (endValue.floatValue() - startFloat); 7 | } 8 | } -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/utils/animation/IntEvaluator.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.utils.animation; 2 | 3 | public class IntEvaluator implements TypeEvaluator { 4 | 5 | public Integer evaluate(float fraction, Integer startValue, Integer endValue) { 6 | int startInt = startValue; 7 | return (int)(startInt + fraction * (endValue - startInt)); 8 | } 9 | } -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/utils/animation/TypeEvaluator.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.utils.animation; 2 | 3 | public interface TypeEvaluator { 4 | public T evaluate(float fraction, T startValue, T endValue); 5 | 6 | } -------------------------------------------------------------------------------- /core/src/com/meizu/taskmanager/utils/eventbus/EventBusUtil.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.utils.eventbus; 2 | 3 | import com.google.common.eventbus.EventBus; 4 | 5 | public class EventBusUtil { 6 | protected static EventBus eventBus; 7 | 8 | public synchronized static EventBus getDefaultEventBus() { 9 | if (eventBus == null) { 10 | eventBus = new EventBus("taskmanager"); 11 | } 12 | return eventBus; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /desktop/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | 3 | sourceCompatibility = 1.7 4 | sourceSets.main.java.srcDirs = [ "src/" ] 5 | 6 | project.ext.mainClassName = "com.meizu.taskmanager.desktop.DesktopLauncher" 7 | project.ext.assetsDir = new File("../android/assets"); 8 | 9 | task run(dependsOn: classes, type: JavaExec) { 10 | main = project.mainClassName 11 | classpath = sourceSets.main.runtimeClasspath 12 | standardInput = System.in 13 | workingDir = project.assetsDir 14 | ignoreExitValue = true 15 | } 16 | 17 | task runDesktop(dependsOn: classes, type: JavaExec) { 18 | main = project.mainClassName 19 | classpath = sourceSets.main.runtimeClasspath 20 | standardInput = System.in 21 | workingDir = project.assetsDir 22 | ignoreExitValue = true 23 | } 24 | 25 | task dist(type: Jar) { 26 | from files(sourceSets.main.output.classesDir) 27 | from files(sourceSets.main.output.resourcesDir) 28 | from {configurations.compile.collect {zipTree(it)}} 29 | from files(project.assetsDir); 30 | 31 | manifest { 32 | attributes 'Main-Class': project.mainClassName 33 | } 34 | } 35 | 36 | dist.dependsOn classes 37 | 38 | eclipse { 39 | project { 40 | name = appName + "-desktop" 41 | linkedResource name: 'assets', type: '2', location: 'PARENT-1-PROJECT_LOC/android/assets' 42 | } 43 | } 44 | 45 | task afterEclipseImport(description: "Post processing after project generation", group: "IDE") { 46 | doLast { 47 | def classpath = new XmlParser().parse(file(".classpath")) 48 | new Node(classpath, "classpathentry", [ kind: 'src', path: 'assets' ]); 49 | def writer = new FileWriter(file(".classpath")) 50 | def printer = new XmlNodePrinter(new PrintWriter(writer)) 51 | printer.setPreserveWhitespace(true) 52 | printer.print(classpath) 53 | } 54 | } -------------------------------------------------------------------------------- /desktop/src/com/meizu/taskmanager/desktop/DesktopLauncher.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.desktop; 2 | 3 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication; 4 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; 5 | import com.meizu.taskmanager.TaskManager; 6 | 7 | public class DesktopLauncher { 8 | public static void main (String[] arg) { 9 | LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); 10 | config.height=800; 11 | config.width=450; 12 | config.disableAudio = true; 13 | new LwjglApplication(new TaskManager(), config); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.daemon=true 2 | org.gradle.jvmargs=-Xms128m -Xmx512m 3 | org.gradle.configureondemand=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Sep 21 13:08:26 CEST 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /html/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | apply plugin: "jetty" 3 | 4 | gwt { 5 | gwtVersion='2.6.0' // Should match the gwt version used for building the gwt backend 6 | maxHeapSize="1G" // Default 256m is not enough for gwt compiler. GWT is HUNGRY 7 | minHeapSize="1G" 8 | 9 | src = files(file("src/")) // Needs to be in front of "modules" below. 10 | modules 'com.meizu.taskmanager.GdxDefinition' 11 | devModules 'com.meizu.taskmanager.GdxDefinitionSuperdev' 12 | project.webAppDirName = 'webapp' 13 | 14 | compiler { 15 | strict = true; 16 | enableClosureCompiler = true; 17 | disableCastChecking = true; 18 | } 19 | } 20 | 21 | task draftRun(type: JettyRunWar) { 22 | dependsOn draftWar 23 | dependsOn.remove('war') 24 | webApp=draftWar.archivePath 25 | daemon=true 26 | } 27 | 28 | task superDev(type: de.richsource.gradle.plugins.gwt.GwtSuperDev) { 29 | dependsOn draftRun 30 | doFirst { 31 | gwt.modules = gwt.devModules 32 | } 33 | } 34 | 35 | task dist(dependsOn: [clean, compileGwt]) { 36 | doLast { 37 | file("build/dist").mkdirs() 38 | copy { 39 | from "build/gwt/out" 40 | into "build/dist" 41 | } 42 | copy { 43 | from "webapp" 44 | into "build/dist" 45 | } 46 | copy { 47 | from "war" 48 | into "build/dist" 49 | } 50 | } 51 | } 52 | 53 | draftWar { 54 | from "war" 55 | } 56 | 57 | task addSource << { 58 | sourceSets.main.compileClasspath += files(project(':core').sourceSets.main.allJava.srcDirs) 59 | } 60 | 61 | tasks.compileGwt.dependsOn(addSource) 62 | tasks.draftCompileGwt.dependsOn(addSource) 63 | 64 | sourceCompatibility = 1.7 65 | sourceSets.main.java.srcDirs = [ "src/" ] 66 | 67 | 68 | eclipse.project { 69 | name = appName + "-html" 70 | } 71 | -------------------------------------------------------------------------------- /html/src/com/meizu/taskmanager/GdxDefinition.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /html/src/com/meizu/taskmanager/GdxDefinitionSuperdev.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /html/src/com/meizu/taskmanager/client/HtmlLauncher.java: -------------------------------------------------------------------------------- 1 | package com.meizu.taskmanager.client; 2 | 3 | import com.badlogic.gdx.ApplicationListener; 4 | import com.badlogic.gdx.backends.gwt.GwtApplication; 5 | import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration; 6 | import com.meizu.taskmanager.TaskManager; 7 | 8 | public class HtmlLauncher extends GwtApplication { 9 | 10 | @Override 11 | public GwtApplicationConfiguration getConfig () { 12 | return new GwtApplicationConfiguration(480, 320); 13 | } 14 | 15 | @Override 16 | public ApplicationListener getApplicationListener () { 17 | return new TaskManager(); 18 | } 19 | } -------------------------------------------------------------------------------- /html/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /html/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TaskManager 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 | 16 | 17 | 32 | 33 | -------------------------------------------------------------------------------- /html/webapp/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/html/webapp/refresh.png -------------------------------------------------------------------------------- /html/webapp/soundmanager2-jsmin.js: -------------------------------------------------------------------------------- 1 | /** @license 2 | 3 | 4 | SoundManager 2: JavaScript Sound for the Web 5 | ---------------------------------------------- 6 | http://schillmania.com/projects/soundmanager2/ 7 | 8 | Copyright (c) 2007, Scott Schiller. All rights reserved. 9 | Code provided under the BSD License: 10 | http://schillmania.com/projects/soundmanager2/license.txt 11 | 12 | V2.97a.20130512 13 | */ 14 | (function(h,g){function fa(fa,wa){function ga(b){return c.preferFlash&&H&&!c.ignoreFlash&&c.flash[b]!==g&&c.flash[b]}function s(b){return function(d){var e=this._s;!e||!e._a?(e&&e.id?c._wD(e.id+": Ignoring "+d.type):c._wD(rb+"Ignoring "+d.type),d=null):d=b.call(this,d);return d}}this.setupOptions={url:fa||null,flashVersion:8,debugMode:!0,debugFlash:!1,useConsole:!0,consoleOnly:!0,waitForWindowLoad:!1,bgColor:"#ffffff",useHighPerformance:!1,flashPollingInterval:null,html5PollingInterval:null,flashLoadTimeout:1E3, 15 | wmode:null,allowScriptAccess:"always",useFlashBlock:!1,useHTML5Audio:!0,html5Test:/^(probably|maybe)$/i,preferFlash:!0,noSWFCache:!1,idPrefix:"sound"};this.defaultOptions={autoLoad:!1,autoPlay:!1,from:null,loops:1,onid3:null,onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onposition:null,onstop:null,onfailure:null,onfinish:null,multiShot:!0,multiShotEvents:!1,position:null,pan:0,stream:!0,to:null,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null, 16 | usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.audioFormats={mp3:{type:['audio/mpeg; codecs\x3d"mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a","m4b"],type:['audio/mp4; codecs\x3d"mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs\x3dvorbis"],required:!1}, 17 | opus:{type:["audio/ogg; codecs\x3dopus","audio/opus"],required:!1},wav:{type:['audio/wav; codecs\x3d"1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.movieID="sm2-container";this.id=wa||"sm2movie";this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.versionNumber="V2.97a.20130512";this.altURL=this.movieURL=this.version=null;this.enabled=this.swfLoaded=!1;this.oMC=null;this.sounds={};this.soundIDs=[];this.didFlashBlock=this.muted=!1;this.filePattern=null;this.filePatterns= 18 | {flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={type:null,types:{remote:"remote (domain-based) rules",localWithFile:"local with file access (no internet access)",localWithNetwork:"local with network (internet access only, no local access)",localTrusted:"local, trusted (local+internet access)"},description:null,noRemote:null,noLocal:null};this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only= 19 | !1;var Ua,c=this,Va=null,k=null,rb="HTML5::",A,t=navigator.userAgent,U=h.location.href.toString(),m=document,xa,Wa,ya,n,F=[],za=!0,C,V=!1,W=!1,q=!1,y=!1,ha=!1,p,sb=0,X,B,Aa,O,Ba,M,P,Q,Xa,Ca,ia,I,ja,Da,R,Ea,Y,ka,la,S,Ya,Fa,Za=["log","info","warn","error"],$a,Ga,ab,Z=null,Ha=null,r,Ia,T,bb,ma,na,J,v,$=!1,Ja=!1,cb,db,eb,oa=0,aa=null,pa,N=[],qa,u=null,fb,ra,ba,K,sa,Ka,gb,w,hb=Array.prototype.slice,E=!1,La,H,Ma,ib,G,jb,Na,ta,kb=0,ca=t.match(/(ipad|iphone|ipod)/i),lb=t.match(/android/i),L=t.match(/msie/i), 20 | tb=t.match(/webkit/i),ua=t.match(/safari/i)&&!t.match(/chrome/i),Oa=t.match(/opera/i),ub=t.match(/firefox/i),Pa=t.match(/(mobile|pre\/|xoom)/i)||ca||lb,Qa=!U.match(/usehtml5audio/i)&&!U.match(/sm2\-ignorebadua/i)&&ua&&!t.match(/silk/i)&&t.match(/OS X 10_6_([3-7])/i),da=h.console!==g&&console.log!==g,Ra=m.hasFocus!==g?m.hasFocus():null,va=ua&&(m.hasFocus===g||!m.hasFocus()),mb=!va,nb=/(mp3|mp4|mpa|m4a|m4b)/i,ea=m.location?m.location.protocol.match(/http/i):null,ob=!ea?"http://":"",pb=/^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|m4b|mp4v|3gp|3g2)\s*(?:$|;)/i, 21 | qb="mpeg4 aac flv mov mp4 m4v f4v m4a m4b mp4v 3gp 3g2".split(" "),vb=RegExp("\\.("+qb.join("|")+")(\\?.*)?$","i");this.mimePattern=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.useAltURL=!ea;var Sa;try{Sa=Audio!==g&&(Oa&&opera!==g&&10>opera.version()?new Audio(null):new Audio).canPlayType!==g}catch(wb){Sa=!1}this.hasHTML5=Sa;this.setup=function(b){var d=!c.url;b!==g&&(q&&u&&c.ok()&&(b.flashVersion!==g||b.url!==g||b.html5Test!==g))&&J(r("setupLate"));Aa(b);b&&(d&&(Y&&b.url!==g)&&c.beginDelayedInit(), 22 | !Y&&(b.url!==g&&"complete"===m.readyState)&&setTimeout(R,1));return c};this.supported=this.ok=function(){return u?q&&!y:c.useHTML5Audio&&c.hasHTML5};this.getMovie=function(c){return A(c)||m[c]||h[c]};this.createSound=function(b,d){function e(){f=ma(f);c.sounds[f.id]=new Ua(f);c.soundIDs.push(f.id);return c.sounds[f.id]}var a,f;a=null;a="soundManager.createSound(): "+r(!q?"notReady":"notOK");if(!q||!c.ok())return J(a),!1;d!==g&&(b={id:b,url:d});f=B(b);f.url=pa(f.url);void 0===f.id&&(f.id=c.setupOptions.idPrefix+ 23 | kb++);f.id.toString().charAt(0).match(/^[0-9]$/)&&c._wD("soundManager.createSound(): "+r("badID",f.id),2);c._wD("soundManager.createSound(): "+f.id+(f.url?" ("+f.url+")":""),1);if(v(f.id,!0))return c._wD("soundManager.createSound(): "+f.id+" exists",1),c.sounds[f.id];if(ra(f))a=e(),c._wD(f.id+": Using HTML5"),a._setup_html5(f);else{if(c.html5Only)return c._wD(f.id+": No HTML5 support for this sound, and no Flash. Exiting."),e();if(c.html5.usingFlash&&f.url&&f.url.match(/data\:/i))return c._wD(f.id+ 24 | ": data: URIs not supported via Flash. Exiting."),e();8a.instanceCount?(m(),e=a._setup_html5(),a.setPosition(a._iO.position),e.play()):(c._wD(a.id+": Cloning Audio() for instance #"+a.instanceCount+"..."),l=new Audio(a._iO.url),z=function(){w.remove(l,"onended",z);a._onfinish(a);sa(l);l=null},h=function(){w.remove(l,"canplay",h);try{l.currentTime=a._iO.position/1E3}catch(c){J(a.id+": multiShot play() failed to apply position of "+a._iO.position/1E3)}l.play()},w.add(l,"ended",z),a._iO.position? 45 | w.add(l,"canplay",h):l.play()):(x=k._start(a.id,a._iO.loops||1,9===n?a.position:a.position/1E3,a._iO.multiShot||!1),9===n&&!x&&(c._wD(e+"No sound hardware, or 32-sound ceiling hit",2),a._iO.onplayerror&&a._iO.onplayerror.apply(a)))}return a};this.stop=function(b){var d=a._iO;1===a.playState&&(c._wD(a.id+": stop()"),a._onbufferchange(0),a._resetOnPosition(0),a.paused=!1,a.isHTML5||(a.playState=0),Ta(),d.to&&a.clearOnPosition(d.to),a.isHTML5?a._a&&(b=a.position,a.setPosition(0),a.position=b,a._a.pause(), 46 | a.playState=0,a._onTimer(),l()):(k._stop(a.id,b),d.serverURL&&a.unload()),a.instanceCount=0,a._iO={},d.onstop&&d.onstop.apply(a));return a};this.setAutoPlay=function(b){c._wD(a.id+": Autoplay turned "+(b?"on":"off"));a._iO.autoPlay=b;a.isHTML5||(k._setAutoPlay(a.id,b),b&&(!a.instanceCount&&1===a.readyState)&&(a.instanceCount++,c._wD(a.id+": Incremented instance count to "+a.instanceCount)))};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(b){b===g&&(b=0);var d=a.isHTML5? 47 | Math.max(b,0):Math.min(a.duration||a._iO.duration,Math.max(b,0));a.position=d;b=a.position/1E3;a._resetOnPosition(a.position);a._iO.position=d;if(a.isHTML5){if(a._a){if(a._html5_canplay){if(a._a.currentTime!==b){c._wD(a.id+": setPosition("+b+")");try{a._a.currentTime=b,(0===a.playState||a.paused)&&a._a.pause()}catch(e){c._wD(a.id+": setPosition("+b+") failed: "+e.message,2)}}}else if(b)return c._wD(a.id+": setPosition("+b+"): Cannot seek yet, sound not ready",2),a;a.paused&&a._onTimer(!0)}}else b= 48 | 9===n?a.position:b,a.readyState&&2!==a.readyState&&k._setPosition(a.id,b,a.paused||!a.playState,a._iO.multiShot);return a};this.pause=function(b){if(a.paused||0===a.playState&&1!==a.readyState)return a;c._wD(a.id+": pause()");a.paused=!0;a.isHTML5?(a._setup_html5().pause(),l()):(b||b===g)&&k._pause(a.id,a._iO.multiShot);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){var b=a._iO;if(!a.paused)return a;c._wD(a.id+": resume()");a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(), 49 | m()):(b.isMovieStar&&!b.serverURL&&a.setPosition(a.position),k._pause(a.id,b.multiShot));!s&&b.onplay?(b.onplay.apply(a),s=!0):b.onresume&&b.onresume.apply(a);return a};this.togglePause=function(){c._wD(a.id+": togglePause()");if(0===a.playState)return a.play({position:9===n&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(b,c){b===g&&(b=0);c===g&&(c=!1);a.isHTML5||k._setPan(a.id,b);a._iO.pan=b;c||(a.pan=b,a.options.pan=b);return a};this.setVolume= 50 | function(b,d){b===g&&(b=100);d===g&&(d=!1);a.isHTML5?a._a&&(a._a.volume=Math.max(0,Math.min(1,b/100))):k._setVolume(a.id,c.muted&&!a.muted||a.muted?0:b);a._iO.volume=b;d||(a.volume=b,a.options.volume=b);return a};this.mute=function(){a.muted=!0;a.isHTML5?a._a&&(a._a.muted=!0):k._setVolume(a.id,0);return a};this.unmute=function(){a.muted=!1;var b=a._iO.volume!==g;a.isHTML5?a._a&&(a._a.muted=!1):k._setVolume(a.id,b?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute(): 51 | a.mute()};this.onposition=this.onPosition=function(b,c,d){D.push({position:parseInt(b,10),method:c,scope:d!==g?d:a,fired:!1});return a};this.clearOnPosition=function(a,b){var c;a=parseInt(a,10);if(isNaN(a))return!1;for(c=0;c=b)return!1;for(b-=1;0<=b;b--)c=D[b],!c.fired&&a.position>=c.position&&(c.fired=!0,t++,c.method.apply(c.scope,[c.position])); 52 | return!0};this._resetOnPosition=function(a){var b,c;b=D.length;if(!b)return!1;for(b-=1;0<=b;b--)c=D[b],c.fired&&a<=c.position&&(c.fired=!1,t--);return!0};y=function(){var b=a._iO,d=b.from,e=b.to,f,g;g=function(){c._wD(a.id+': "To" time of '+e+" reached.");a.clearOnPosition(e,g);a.stop()};f=function(){c._wD(a.id+': Playing "from" '+d);if(null!==e&&!isNaN(e))a.onPosition(e,g)};null!==d&&!isNaN(d)&&(b.position=d,b.multiShot=!1,f());return b};q=function(){var b,c=a._iO.onposition;if(c)for(b in c)if(c.hasOwnProperty(b))a.onPosition(parseInt(b, 53 | 10),c[b])};Ta=function(){var b,c=a._iO.onposition;if(c)for(b in c)c.hasOwnProperty(b)&&a.clearOnPosition(parseInt(b,10))};m=function(){a.isHTML5&&cb(a)};l=function(){a.isHTML5&&db(a)};f=function(b){b||(D=[],t=0);s=!1;a._hasTimer=null;a._a=null;a._html5_canplay=!1;a.bytesLoaded=null;a.bytesTotal=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.buffered=[];a.eqData=[];a.eqData.left=[];a.eqData.right=[];a.failures=0;a.isBuffering=!1;a.instanceOptions={};a.instanceCount= 54 | 0;a.loaded=!1;a.metadata={};a.readyState=0;a.muted=!1;a.paused=!1;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.playState=0;a.position=null;a.id3={}};f();this._onTimer=function(b){var c,f=!1,g={};if(a._hasTimer||b){if(a._a&&(b||(0opera.version()?new Audio(null):new Audio,c=a._a,c._called_load=!1,E&&(Va=c);a.isHTML5=!0;a._a=c;c._s=a;h();a._apply_loop(c,b.loops);b.autoLoad||b.autoPlay?a.load():(c.autobuffer=!1,c.preload="auto");return c};h=function(){if(a._a._added_events)return!1;var b;a._a._added_events=!0;for(b in G)G.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,G[b],!1);return!0};z=function(){var b;c._wD(a.id+": Removing event listeners"); 57 | a._a._added_events=!1;for(b in G)G.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,G[b],!1)};this._onload=function(b){var d=!!b||!a.isHTML5&&8===n&&a.duration;b=a.id+": ";c._wD(b+(d?"onload()":"Failed to load / invalid sound?"+(!a.duration?" Zero-length duration reported.":" -")+" ("+a.url+")"),d?1:2);!d&&!a.isHTML5&&(!0===c.sandbox.noRemote&&c._wD(b+r("noNet"),1),!0===c.sandbox.noLocal&&c._wD(b+r("noLocal"),1));a.loaded=d;a.readyState=d?3:2;a._onbufferchange(0);a._iO.onload&&ta(a,function(){a._iO.onload.apply(a, 58 | [d])});return!0};this._onbufferchange=function(b){if(0===a.playState||b&&a.isBuffering||!b&&!a.isBuffering)return!1;a.isBuffering=1===b;a._iO.onbufferchange&&(c._wD(a.id+": Buffer state change: "+b),a._iO.onbufferchange.apply(a));return!0};this._onsuspend=function(){a._iO.onsuspend&&(c._wD(a.id+": Playback suspended"),a._iO.onsuspend.apply(a));return!0};this._onfailure=function(b,d,e){a.failures++;c._wD(a.id+": Failures \x3d "+a.failures);if(a._iO.onfailure&&1===a.failures)a._iO.onfailure(a,b,d,e); 59 | else c._wD(a.id+": Ignoring failure")};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);a._resetOnPosition(0);if(a.instanceCount&&(a.instanceCount--,a.instanceCount||(Ta(),a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},l(),a.isHTML5&&(a.position=0)),(!a.instanceCount||a._iO.multiShotEvents)&&b))c._wD(a.id+": onfinish()"),ta(a,function(){b.apply(a)})};this._whileloading=function(b,c,d,e){var f=a._iO;a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d); 60 | a.bufferLength=e;a.durationEstimate=!a.isHTML5&&!f.isMovieStar?f.duration?a.duration>f.duration?a.duration:f.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10):a.duration;a.isHTML5||(a.buffered=[{start:0,end:a.duration}]);(3!==a.readyState||a.isHTML5)&&f.whileloading&&f.whileloading.apply(a)};this._whileplaying=function(b,c,d,e,f){var l=a._iO;if(isNaN(b)||null===b)return!1;a.position=Math.max(0,b);a._processOnPosition();!a.isHTML5&&8opera.version()?new Audio(null):new Audio:null,e,a,f={},h;h=c.audioFormats;for(e in h)if(h.hasOwnProperty(e)&&(a="audio/"+e,f[e]=b(h[e].type),f[a]=f[e],e.match(nb)?(c.flash[e]=!0,c.flash[a]=!0):(c.flash[e]=!1,c.flash[a]=!1),h[e]&&h[e].related))for(a=h[e].related.length- 74 | 1;0<=a;a--)f["audio/"+h[e].related[a]]=f[e],c.html5[h[e].related[a]]=f[e],c.flash[h[e].related[a]]=f[e];f.canPlayType=d?b:null;c.html5=B(c.html5,f);c.html5.usingFlash=fb();u=c.html5.usingFlash;return!0};I={notReady:"Unavailable - wait until onready() has fired.",notOK:"Audio support is not available.",domError:"soundManagerexception caught while appending SWF to DOM.",spcWmode:"Removing wmode, preventing known SWF loading issue(s)",swf404:"soundManager: Verify that %s is a valid path.",tryDebug:"Try soundManager.debugFlash \x3d true for more security details (output goes to SWF.)", 75 | checkSWF:"See SWF output for more debug info.",localFail:"soundManager: Non-HTTP page ("+m.location.protocol+" URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/",waitFocus:"soundManager: Special case: Waiting for SWF to load with window focus...",waitForever:"soundManager: Waiting indefinitely for Flash (will recover if unblocked)...", 76 | waitSWF:"soundManager: Waiting for 100% SWF load...",needFunction:"soundManager: Function object expected for %s",badID:'Sound ID "%s" should be a string, starting with a non-numeric character',currentObj:"soundManager: _debug(): Current sound objects",waitOnload:"soundManager: Waiting for window.onload()",docLoaded:"soundManager: Document already loaded",onload:"soundManager: initComplete(): calling soundManager.onload()",onloadOK:"soundManager.onload() complete",didInit:"soundManager: init(): Already called?", 77 | secNote:"Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html",badRemove:"soundManager: Failed to remove Flash node.",shutdown:"soundManager.disable(): Shutting down",queue:"soundManager: Queueing %s handler",smError:"SMSound.load(): Exception: JS-Flash communication failed, or JS error.",fbTimeout:"No flash response, applying .swf_timedout CSS...", 78 | fbLoaded:"Flash loaded",fbHandler:"soundManager: flashBlockHandler()",manURL:"SMSound.load(): Using manually-assigned URL",onURL:"soundManager.load(): current URL already assigned.",badFV:'soundManager.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.',as2loop:"Note: Setting stream:false so looping can work (flash 8 limitation)",noNSLoop:"Note: Looping not implemented for MovieStar formats",needfl9:"Note: Switching to flash 9, required for MP4 formats.",mfTimeout:"Setting flashLoadTimeout \x3d 0 (infinite) for off-screen, mobile flash case", 79 | needFlash:"soundManager: Fatal error: Flash is needed to play some required formats, but is not available.",gotFocus:"soundManager: Got window focus.",policy:"Enabling usePolicyFile for data access",setup:"soundManager.setup(): allowed parameters: %s",setupError:'soundManager.setup(): "%s" cannot be assigned with this method.',setupUndef:'soundManager.setup(): Could not find option "%s"',setupLate:"soundManager.setup(): url, flashVersion and html5Test property changes will not take effect until reboot().", 80 | noURL:"soundManager: Flash URL required. Call soundManager.setup({url:...}) to get started.",sm2Loaded:"SoundManager 2: Ready.",reset:"soundManager.reset(): Removing event callbacks",mobileUA:"Mobile UA detected, preferring HTML5 by default.",globalHTML5:"Using singleton HTML5 Audio() pattern for this device."};r=function(){var b=hb.call(arguments),c=b.shift(),c=I&&I[c]?I[c]:"",e,a;if(c&&b&&b.length){e=0;for(a=b.length;en)&&(c._wD(r("needfl9")),c.flashVersion=n=9);c.version=c.versionNumber+(c.html5Only?" (HTML5-only mode)": 83 | 9===n?" (AS3/Flash 9)":" (AS2/Flash 8)");8b&&(d= 102 | !0));setTimeout(function(){b=c.getMoviePercent();if(d)return $=!1,c._wD(r("waitSWF")),h.setTimeout(Q,1),!1;q||(c._wD("soundManager: No Flash response within expected time. Likely causes: "+(0===b?"SWF load failed, ":"")+"Flash blocked or JS-Flash security error."+(c.debugFlash?" "+r("checkSWF"):""),2),!ea&&b&&(p("localFail",2),c.debugFlash||p("tryDebug",2)),0===b&&c._wD(r("swf404",c.url),1),C("flashtojs",!1,": Timed out"+ea?" (Check flash security or flash blockers)":" (No plugin/missing SWF?)")); 103 | !q&&mb&&(null===b?c.useFlashBlock||0===c.flashLoadTimeout?(c.useFlashBlock&&Ia(),p("waitForever")):!c.useFlashBlock&&qa?h.setTimeout(function(){J("soundManager: useFlashBlock is false, 100% HTML5 mode is possible. Rebooting with preferFlash: false...");c.setup({preferFlash:!1}).reboot();c.didFlashBlock=!0;c.beginDelayedInit()},1):(p("waitForever"),M({type:"ontimeout",ignoreInit:!0})):0===c.flashLoadTimeout?p("waitForever"):Ga(!0))},c.flashLoadTimeout)};ia=function(){if(Ra||!va)return w.remove(h,"focus", 104 | ia),!0;Ra=mb=!0;p("gotFocus");$=!1;Q();w.remove(h,"focus",ia);return!0};Na=function(){N.length&&(c._wD("SoundManager 2: "+N.join(" "),1),N=[])};jb=function(){Na();var b,d=[];if(c.useHTML5Audio&&c.hasHTML5){for(b in c.audioFormats)c.audioFormats.hasOwnProperty(b)&&d.push(b+" \x3d "+c.html5[b]+(!c.html5[b]&&u&&c.flash[b]?" (using flash)":c.preferFlash&&c.flash[b]&&u?" (preferring flash)":!c.html5[b]?" ("+(c.audioFormats[b].required?"required, ":"")+"and no flash support)":""));c._wD("SoundManager 2 HTML5 support: "+ 105 | d.join(", "),1)}};X=function(b){if(q)return!1;if(c.html5Only)return p("sm2Loaded"),q=!0,P(),C("onload",!0),!0;var d=!0,e;if(!c.useFlashBlock||!c.flashLoadTimeout||c.getMoviePercent())q=!0,y&&(e={type:!H&&u?"NO_FLASH":"INIT_TIMEOUT"});c._wD("SoundManager 2 "+(y?"failed to load":"loaded")+" ("+(y?"Flash security/load error":"OK")+")",y?2:1);y||b?(c.useFlashBlock&&c.oMC&&(c.oMC.className=T()+" "+(null===c.getMoviePercent()?"swf_timedout":"swf_error")),M({type:"ontimeout",error:e,ignoreInit:!0}),C("onload", 106 | !1),S(e),d=!1):C("onload",!0);y||(c.waitForWindowLoad&&!ha?(p("waitOnload"),w.add(h,"load",P)):(c.waitForWindowLoad&&ha&&p("docLoaded"),P()));return d};Wa=function(){var b,d=c.setupOptions;for(b in d)d.hasOwnProperty(b)&&(c[b]===g?c[b]=d[b]:c[b]!==d[b]&&(c.setupOptions[b]=c[b]))};ya=function(){if(q)return p("didInit"),!1;if(c.html5Only)return q||(w.remove(h,"load",c.beginDelayedInit),c.enabled=!0,X()),!0;ja();try{k._externalInterfaceTest(!1),Ya(!0,c.flashPollingInterval||(c.useHighPerformance?10: 107 | 50)),c.debugMode||k._disableDebug(),c.enabled=!0,C("jstoflash",!0),c.html5Only||w.add(h,"unload",xa)}catch(b){return c._wD("js/flash exception: "+b.toString()),C("jstoflash",!1),S({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),Ga(!0),X(),!1}X();w.remove(h,"load",c.beginDelayedInit);return!0};R=function(){if(Y)return!1;Y=!0;Wa();Fa();var b=null,b=null,d=U.toLowerCase();-1!==d.indexOf("sm2-usehtml5audio\x3d")&&(b="1"===d.charAt(d.indexOf("sm2-usehtml5audio\x3d")+18),da&&console.log((b?"Enabling ":"Disabling ")+ 108 | "useHTML5Audio via URL parameter"),c.setup({useHTML5Audio:b}));-1!==d.indexOf("sm2-preferflash\x3d")&&(b="1"===d.charAt(d.indexOf("sm2-preferflash\x3d")+16),da&&console.log((b?"Enabling ":"Disabling ")+"preferFlash via URL parameter"),c.setup({preferFlash:b}));!H&&c.hasHTML5&&(c._wD("SoundManager: No Flash detected"+(!c.useHTML5Audio?", enabling HTML5.":". Trying HTML5-only mode."),1),c.setup({useHTML5Audio:!0,preferFlash:!1}));gb();!H&&u&&(N.push(I.needFlash),c.setup({flashLoadTimeout:1}));m.removeEventListener&& 109 | m.removeEventListener("DOMContentLoaded",R,!1);ja();return!0};Ka=function(){"complete"===m.readyState&&(R(),m.detachEvent("onreadystatechange",Ka));return!0};Ea=function(){ha=!0;w.remove(h,"load",Ea)};Da=function(){if(Pa&&((!c.setupOptions.useHTML5Audio||c.setupOptions.preferFlash)&&N.push(I.mobileUA),c.setupOptions.useHTML5Audio=!0,c.setupOptions.preferFlash=!1,ca||lb&&!t.match(/android\s2\.3/i)))N.push(I.globalHTML5),ca&&(c.ignoreFlash=!0),E=!0};Da();Ma();w.add(h,"focus",ia);w.add(h,"load",Q);w.add(h, 110 | "load",Ea);m.addEventListener?m.addEventListener("DOMContentLoaded",R,!1):m.attachEvent?m.attachEvent("onreadystatechange",Ka):(C("onload",!1),S({type:"NO_DOM2_EVENTS",fatal:!0}))}var wa=null;if(void 0===h.SM2_DEFER||!SM2_DEFER)wa=new fa;h.SoundManager=fa;h.soundManager=wa})(window); -------------------------------------------------------------------------------- /html/webapp/soundmanager2-setup.js: -------------------------------------------------------------------------------- 1 | window.SM2_DEFER = true; -------------------------------------------------------------------------------- /html/webapp/styles.css: -------------------------------------------------------------------------------- 1 | canvas { 2 | cursor: default; 3 | outline: none; 4 | } 5 | 6 | body { 7 | background-color: #222222; 8 | } 9 | 10 | .superdev { 11 | color: rgb(37,37,37); 12 | text-shadow: 0px 1px 1px rgba(250,250,250,0.1); 13 | font-size: 50pt; 14 | display: block; 15 | position: relative; 16 | text-decoration: none; 17 | background-color: rgb(83,87,93); 18 | box-shadow: 0px 3px 0px 0px rgb(34,34,34), 19 | 0px 7px 10px 0px rgb(17,17,17), 20 | inset 0px 1px 1px 0px rgba(250, 250, 250, .2), 21 | inset 0px -12px 35px 0px rgba(0, 0, 0, .5); 22 | width: 70px; 23 | height: 70px; 24 | border: 0; 25 | border-radius: 35px; 26 | text-align: center; 27 | line-height: 68px; 28 | } 29 | 30 | .superdev:active { 31 | box-shadow: 0px 0px 0px 0px rgb(34,34,34), 32 | 0px 3px 7px 0px rgb(17,17,17), 33 | inset 0px 1px 1px 0px rgba(250, 250, 250, .2), 34 | inset 0px -10px 35px 5px rgba(0, 0, 0, .5); 35 | background-color: rgb(83,87,93); 36 | top: 3px; 37 | color: #fff; 38 | text-shadow: 0px 0px 3px rgb(250,250,250); 39 | } 40 | 41 | .superdev:hover { 42 | background-color: rgb(100,100,100); 43 | } 44 | -------------------------------------------------------------------------------- /screen-record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenaiX/TaskManager/22596a45f0f8a5d5b8bc3f06d66de51827d57346/screen-record.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'desktop' 2 | include 'android' 3 | include 'html' 4 | include 'core' --------------------------------------------------------------------------------