Skip to content

Commit

Permalink
Big! Minizes to taskbar now. Automatically launches minimized if star…
Browse files Browse the repository at this point in the history
…ted using arguments
  • Loading branch information
chaorace committed May 18, 2016
1 parent a4f6b53 commit d0c3cbb
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 34 deletions.
132 changes: 105 additions & 27 deletions src/main/java/GUI.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import java.awt.event.{ActionEvent, ActionListener}
import java.awt.{MenuItem, PopupMenu, SystemTray, TrayIcon}
import java.io.FileInputStream
import java.lang.Boolean
import javafx.beans.value.{ChangeListener, ObservableValue}
import javax.imageio.ImageIO

import org.jnativehook.GlobalScreen

import scalafx.application.JFXApp
import scalafx.application.{JFXApp, Platform}
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.control.Alert.AlertType
import scalafx.scene.control._
import scalafx.scene.layout.{VBox, HBox, FlowPane, BorderPane}
import scalafx.scene.layout.{BorderPane, FlowPane, HBox, VBox}
import scalafx.scene.paint.Color
import scalafx.Includes._
import scalafx.scene.text.Font
Expand All @@ -15,16 +22,21 @@ import scalafx.scene.text.Font
/**
* Created by Chris on 8/4/2015. This is the GUI wrapper for the engine. This can be completely bypassed by console commands
*/
class Gui extends JFXApp {
class Gui(startHidden: Boolean, config: Config) extends JFXApp {
Platform.implicitExit = false
var engineThread:Thread = null
var engine = false

//GUI inputfields
val pollingField = new InputField("Polling Rate", Tooltip(Main.pollingRateDesc)){inputBox.text = config.pollingRate.getOrElse("").toString}
val startupField = new InputField("Tolerance", Tooltip(Main.startupThresholdDesc)){inputBox.text = config.startupThreshold.getOrElse("").toString}
val giveupField = new InputField("Sensitivity", Tooltip(Main.giveupThresholdDesc)){inputBox.text = config.giveupThreshold.getOrElse("").toString}
val dragField = new InputField("Friction", Tooltip(Main.dragDesc)){inputBox.text = config.drag.getOrElse("").toString}

//Gui setup
stage = new PrimaryStage {
title = s"${Main.name} by ${Main.author}"
scene = new Scene {
val pollingField = new InputField("Polling Rate", Tooltip(Main.pollingRateDesc))
val startupField = new InputField("Tolerance", Tooltip(Main.startupThresholdDesc))
val giveupField = new InputField("Sensitivity", Tooltip(Main.giveupThresholdDesc))
val dragField = new InputField("Friction", Tooltip(Main.dragDesc))

fill = Color.Beige
content = new BorderPane {
padding = Insets(15)
Expand Down Expand Up @@ -53,35 +65,101 @@ class Gui extends JFXApp {
}
//Engine starting logic. Converts fields to values to be used by the engine
bottom = new ToggleButton{
var engineThread:Thread = null
text <== when(selected) choose "Stop/Reload Settings" otherwise "Start"
onAction = handle {selected.value match{
case true =>
try{
engineThread = new Thread(new Engine(new Config(pollingField.value, startupField.value, giveupField.value, dragField.value)))
engineThread.start()
}catch{
case e: NumberFormatException =>
new Alert(AlertType.Error, "Bad value entry").show()
selected.value = false
}
case false => engineThread.stop()
}}
//If the user tries closing the GUI while the engine is running, the thread gets shut down
onCloseRequest = handle {
GlobalScreen.unregisterNativeHook()
if(engineThread != null) engineThread.stop()

def updateText = text = if(engine) "Stop/Reload Settings" else "Start"
updateText
onAction = handle {
engineToggler()
updateText
}
onShowing = handle{
updateText
}
}
//If the user minimizes the GUI, send it to the system tray
iconified.addListener(new ChangeListener[Boolean] {
override def changed(observable: ObservableValue[_ <: Boolean], oldValue: Boolean, newValue: Boolean): Unit = {
if(iconified.value){toggleTray(true)}
}
})
//If the user tries closing the GUI while the engine is running, the thread gets shut down
onCloseRequest = handle {
GlobalScreen.unregisterNativeHook()
toggleTray(false)
if(engineThread != null) engineThread.stop()
Platform.exit()
}

}
}
}

//Tray icon setup
val tray = SystemTray.getSystemTray
val defaultAction = new ActionListener(){
override def actionPerformed(e: ActionEvent): Unit = {
Platform.runLater(toggleTray(false))
}
}
val engineAction = new ActionListener(){
override def actionPerformed(e: ActionEvent): Unit = {
Platform.runLater(engineToggler())
}
}
val showGuiItem = new MenuItem("Show GUI")
showGuiItem.addActionListener(defaultAction)
val toggleEngineItem = new MenuItem("On/Off Toggle")
toggleEngineItem.addActionListener(engineAction)
val popup = new PopupMenu()
popup.add(showGuiItem)
popup.add(toggleEngineItem)
val image = ImageIO.read(getClass.getResourceAsStream("icon.png"))
val trayIcon = new TrayIcon(image, Main.name, popup)
trayIcon.addActionListener(defaultAction)

//If set to start hidden, start hidden
if(startHidden){
toggleTray(true)
}

//Hides and shows GUI
def toggleTray(t: Boolean): Unit ={
//There were basically no references on the internet for how to do this using JFX8, so AWT it is
if(t){
//If true, hide stage and insert tray icon. Otherwise, show stage and remove tray icon

if(SystemTray.isSupported){
stage.hide()
tray.add(trayIcon)
}
}else{
stage.setIconified(false)
stage.show()
tray.remove(trayIcon)
}
}

def engineToggler(): Unit ={
engine match{
case false =>
engine = true
try{
engineThread = new Thread(new Engine(new Config(pollingField.value, startupField.value, giveupField.value, dragField.value)))
engineThread.start()
}catch{
case e: NumberFormatException =>
new Alert(AlertType.Error, "Bad value entry").show()
engine = false
}
case true => engineThread.stop(); engine = false
}
}
}

class InputField(description: String, tt: Tooltip) extends HBox {
//Template for input fields with a built-in description and tooltip
padding = Insets(5)
private val inputBox = new TextField {
val inputBox = new TextField {
maxWidth = 40
}
children = List(new Label(description + ": ") {
Expand Down
17 changes: 10 additions & 7 deletions src/main/java/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import com.beust.jcommander.{JCommander, Parameter}
* Created by Chris on 8/4/2015. Main execution environment
*/

case class Config(pollingRate: Option[Double], startupThreshold: Option[Double], giveupThreshold: Option[Double], drag: Option[Double])
case class Config(pollingRate: Option[Double] = None, startupThreshold: Option[Double] = None, giveupThreshold: Option[Double] = None, drag: Option[Double] = None)


object Main extends App {

//Strings
final val name = "Virtual Trackball"
final val version = "1.0"
Expand Down Expand Up @@ -54,7 +56,7 @@ object Main extends App {
override def main(args: Array[String]): Unit = {
//If there are no command line arguments, boot to gui
if (args.isEmpty) {
val gui = new Gui
val gui = new Gui(false, Config())
gui.main(new Array[String](0))
} else {
//An unreasonable amount of work to get a generally crummy library to play nice with Scala. 0/10 experience, would not recommend JCommander for Scala use
Expand Down Expand Up @@ -83,14 +85,15 @@ object Main extends App {
}

//Start engine with provided parameters

val engine = new Engine(new Config(pollingRate, startupThreshold, giveupThreshold, drag))
engine.run()
val gui = new Gui(true, new Config(pollingRate, startupThreshold, giveupThreshold, drag))
// val engine = new Engine(new Config(pollingRate, startupThreshold, giveupThreshold, drag))
// engine.run()
}catch{
//If anything goes wrong at all, give up and run with defaults
case e: Exception =>
val engine = new Engine(new Config(None, None, None, None))
engine.run()
val gui = new Gui(true, Config())
// val engine = new Engine(Config())
// engine.run()
}
}
}
Expand Down
Binary file added src/main/resources/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d0c3cbb

Please sign in to comment.