diff --git a/README b/README new file mode 100644 index 0000000..6fd65b8 --- /dev/null +++ b/README @@ -0,0 +1 @@ +This is the repo for ZenWriterFX - constructed by a group of geeks at the Java Posse Roundup 2010 diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..6fca96a --- /dev/null +++ b/build.xml @@ -0,0 +1,69 @@ + + + + + + Builds, tests, and runs the project ZenWriterFX. + + + diff --git a/docs/._theme-list.xml b/docs/._theme-list.xml new file mode 100644 index 0000000..9e33906 Binary files /dev/null and b/docs/._theme-list.xml differ diff --git a/docs/theme-list.xml b/docs/theme-list.xml new file mode 100644 index 0000000..2595e87 --- /dev/null +++ b/docs/theme-list.xml @@ -0,0 +1,35 @@ + + + Blades + watergrass + ZenWriter-BG005.JPG + ffffff + 0.3 + 20481536 + + vertical + + + + Sky + skycloudssunset + ZenWriter-BG012.JPG + ffffff + 0.3 + 20481536 + + vertical + + + + Lilly + watercloudslilly pads + ZenWriter-BG023.JPG + ffffff + 0.4 + 20481536 + + vertical + + + \ No newline at end of file diff --git a/manifest.mf b/manifest.mf new file mode 100644 index 0000000..328e8e5 --- /dev/null +++ b/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml new file mode 100644 index 0000000..9e69ae9 --- /dev/null +++ b/nbproject/build-impl.xml @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set build.dir + Must set dist.dir + Must set dist.javadoc.dir + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/configs/DraggableLineBorder.properties b/nbproject/configs/DraggableLineBorder.properties new file mode 100644 index 0000000..817cb07 --- /dev/null +++ b/nbproject/configs/DraggableLineBorder.properties @@ -0,0 +1,3 @@ +execution.target=standard +javafx.profile=desktop +main.class=zen.like.DraggableLineBorder diff --git a/nbproject/configs/LineBorder.properties b/nbproject/configs/LineBorder.properties new file mode 100644 index 0000000..c04058b --- /dev/null +++ b/nbproject/configs/LineBorder.properties @@ -0,0 +1,3 @@ +execution.target=standard +javafx.profile=desktop +main.class=zen.like.LineBorder diff --git a/nbproject/configs/WorkMenuButton.properties b/nbproject/configs/WorkMenuButton.properties new file mode 100644 index 0000000..5323952 --- /dev/null +++ b/nbproject/configs/WorkMenuButton.properties @@ -0,0 +1,3 @@ +execution.target=standard +javafx.profile=desktop +main.class=zen.like.WorkMenuButton diff --git a/nbproject/configs/browser.properties b/nbproject/configs/browser.properties new file mode 100644 index 0000000..7068261 --- /dev/null +++ b/nbproject/configs/browser.properties @@ -0,0 +1,3 @@ +$label=Browser +execution.target=applet +javafx.profile=desktop diff --git a/nbproject/configs/mobile.properties b/nbproject/configs/mobile.properties new file mode 100644 index 0000000..0adf919 --- /dev/null +++ b/nbproject/configs/mobile.properties @@ -0,0 +1,3 @@ +$label=Mobile +execution.target=midp +javafx.profile=mobile diff --git a/nbproject/configs/webstart.properties b/nbproject/configs/webstart.properties new file mode 100644 index 0000000..cf2a2ce --- /dev/null +++ b/nbproject/configs/webstart.properties @@ -0,0 +1,3 @@ +$label=Web Start +execution.target=jnlp +javafx.profile=desktop diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties new file mode 100644 index 0000000..ac68ef3 --- /dev/null +++ b/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=0b6a6bea +build.xml.script.CRC32=7f11d37e +build.xml.stylesheet.CRC32=bdec6f99@1.9.1 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=0b6a6bea +nbproject/build-impl.xml.script.CRC32=0e3c433d +nbproject/build-impl.xml.stylesheet.CRC32=08b52d4e@1.9.1 diff --git a/nbproject/project.properties b/nbproject/project.properties new file mode 100644 index 0000000..fc1913b --- /dev/null +++ b/nbproject/project.properties @@ -0,0 +1,52 @@ +applet.draggable=true +applet.height=200 +applet.width=200 +application.title=ZenWriterFX +application.vendor=dick +build.classes.excludes=**/*.java,**/*.form,**/*.fx +build.classpath=\ + ${javac.classpath}:\ + ${src.dir}:\ + ${build.classes.dir}: +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +debug.classpath=\ + ${run.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/ZenWriterFX.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +includes=** +jar.compress=true +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javadoc.additionalparam= +javadoc.author=true +javadoc.encoding= +javadoc.private=true +javadoc.version=false +javafx.profile=desktop +jnlp.codebase.type=local +jnlp.offline-allowed=true +jnlp.packEnabled=false +jnlp.signed=false +main.class=zenwriterfx.Main +pack200.jar.compress=true +platform.active=default_fx_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs=-Djavafx.allowTransparentStage=true +source.encoding=UTF-8 +src.dir=src diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..7a04216 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,13 @@ + + + org.netbeans.modules.javafx.project + + + ZenWriterFX + 1.6.5 + + + + + + diff --git a/src/zen/like/AbstractMenuButton.fx b/src/zen/like/AbstractMenuButton.fx new file mode 100644 index 0000000..0e1c9bf --- /dev/null +++ b/src/zen/like/AbstractMenuButton.fx @@ -0,0 +1,139 @@ +/* + * MenuButton.fx + * + * Created on 15-Mar-2010, 15:55:06 + */ + +package zen.like; + +import javafx.scene.CustomNode; +import javafx.scene.Group; +import javafx.scene.paint.Color; +import javafx.scene.Node; +import javafx.scene.layout.Resizable; +import javafx.scene.layout.Container; +import javafx.scene.shape.Ellipse; +import javafx.scene.input.MouseEvent; + +/** + * Menubutton component + * @author Peter Pilgrim at the Java Posse Roundup 2010 + */ +public abstract class AbstractMenuButton extends CustomNode, Resizable { + + override var width = 64 on replace { + computeLayout(); + } + override var height = 64 on replace { + computeLayout(); + } + /** margin size */ + public var margin: Number = 4 on replace { + computeLayout(); + }; + + /** action event */ + public var onAction: function(): Void; + + + /** background of the icon */ + public var background: Color = Color.WHITE; + /** icon color when mouse hovers over the button */ + public var hoverColor: Color = Color.GREY; + /** icon color when mouse button is pressed */ + public var downColor: Color = Color.LIGHTBLUE; + + /** the border size of the icon ellipse */ + public var borderWidth: Number = 2; + /** the border colour of the icon ellipse */ + public var borderColor: Color = Color.BLACK; + + /** The icon face */ + protected var faceNode: Node on replace { + if ( isInitialized(faceNode)) { + computeLayout(); + } + }; + + protected var backNode: Ellipse; + protected var faceClipperNode: Ellipse = Ellipse{}; + + public override function create(): Node { + faceNode = createIconFaceNode(); + return Group { + + onMouseClicked: function (e: MouseEvent): Void { + fireAction(); + } + onMousePressed: function (e: MouseEvent): Void { + backNode.fill = downColor; + } + onMouseReleased: function (e: MouseEvent): Void { + backNode.fill = if (hover) hoverColor else background; + } + onMouseEntered: function (e: MouseEvent): Void { + backNode.fill = hoverColor; + } + onMouseExited: function (e: MouseEvent): Void { + backNode.fill = background; + } + + content: [ + backNode = Ellipse { + centerX: bind width/2, centerY: bind height/2 + radiusX: bind width/2, radiusY: bind height/2 + fill: background + stroke: bind borderColor + strokeWidth: bind borderWidth + }, + Group { + clip: faceClipperNode + content: faceNode + } + ] + }; + } + + public abstract function createIconFaceNode(): Node; + + protected function computeLayout(): Void { + + var itemWidth = width - 2*margin; + var itemHeight = height - 2*margin; + Container.layoutNode(faceNode, margin, margin, itemWidth, itemHeight); + + // Create the clipper + faceClipperNode.centerX = itemWidth / 2 + margin; + faceClipperNode.centerY = itemHeight / 2 + margin; + faceClipperNode.radiusX = itemWidth / 2; + faceClipperNode.radiusY = itemHeight / 2; + + } + + protected function fireAction(): Void { + if ( onAction != null) { + onAction(); + } + + } + + public override function getPrefWidth(height: Number) : Number + { + return if ( width > 0) width else -1 + } + + public override function getPrefHeight(width: Number) : Number + { + return if ( height > 0) height else -1 + } + +} + +// Github commands +// Never going remember// git pull dickwallrepo master +// git pull dickwallrepo master +// git pull +// git push +// git push origin master +// + diff --git a/src/zen/like/AntiAliasedTextArea.java b/src/zen/like/AntiAliasedTextArea.java new file mode 100644 index 0000000..6129ef5 --- /dev/null +++ b/src/zen/like/AntiAliasedTextArea.java @@ -0,0 +1,23 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package zen.like; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import javax.swing.JTextPane; + +public class AntiAliasedTextArea extends JTextPane +{ + @Override + public void paint(Graphics g) + { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + super.paint(g); + } +} diff --git a/src/zen/like/DraggableLineBorder.fx b/src/zen/like/DraggableLineBorder.fx new file mode 100644 index 0000000..55a977b --- /dev/null +++ b/src/zen/like/DraggableLineBorder.fx @@ -0,0 +1,334 @@ +/* + * DraggableLineBorder.fx + * + * Created on 06-Apr-2010, 08:29:40 + */ + +package zen.like; + +import javafx.scene.CustomNode; +import javafx.scene.Node; +import javafx.scene.Group; +import javafx.stage.Stage; +import javafx.scene.Scene; +import javafx.scene.Cursor; +import javafx.scene.layout.Resizable; +import javafx.scene.layout.Container; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Font; +import javafx.ext.swing.SwingComponent; +import javafx.scene.input.MouseEvent; +import javafx.util.Math; + +def STEP=10; + + +/** + * Draggable line boder + * @author Peter + */ +public class DraggableLineBorder extends CustomNode, Resizable { + + public var margin: Number = 10 on replace { + scheduleLayout(); + }; + + public-init var item: Node; + + override var width on replace { + scheduleLayout(); + } + override var height on replace { + scheduleLayout(); + } + + public var marginWidth: Number = 10; + public var marginHeight: Number = 10; + public var minimumWidth: Number = 100; + public var minimumHeight: Number = 100; + public var maximumWidth: Number = 1000; + public var maximumHeight: Number = 1000; + + public var borderStrokeColor: Color = Color.BLACK; + public var borderFillColor: Color = Color.TRANSPARENT; + public var borderWidth: Number = 2; + public var dragNodeSize: Number = 10 on replace { + if ( isInitialized(dragNodeSize) ) { + for ( dn in dragNodes) { + dn.size = dragNodeSize; + } + } + }; + + + protected var debugRect = Rectangle { + width: bind width + height: bind height + fill: Color.web("#FFE0E0") + stroke: Color.BLACK strokeWidth: 1 + }; + + protected var border = Rectangle { + strokeWidth: bind borderWidth; + strokeDashOffset: 4 + strokeDashArray: [ 4, 8 ] + stroke: bind borderStrokeColor; + fill: bind borderFillColor; + }; + + protected var n = DragNode{id: "n", hoverCursor: Cursor.N_RESIZE }; + protected var ne = DragNode{id: "ne", hoverCursor: Cursor.NE_RESIZE }; + protected var e = DragNode{id: "e", hoverCursor: Cursor.E_RESIZE }; + protected var se = DragNode{id: "se", hoverCursor: Cursor.SE_RESIZE }; + protected var s = DragNode{id: "s", hoverCursor: Cursor.S_RESIZE }; + protected var sw = DragNode{id: "sw", hoverCursor: Cursor.SW_RESIZE }; + protected var w = DragNode{id: "w", hoverCursor: Cursor.W_RESIZE }; + protected var nw = DragNode{id: "nw", hoverCursor: Cursor.NW_RESIZE }; + protected var dragNodes: DragNode[] = [ n, ne, e, se, s, sw, w, nw ]; + + /** Relayout flag */ + protected var needRelayout: Boolean; + + /** Reschedule a relayout on the EDT */ + protected function scheduleLayout(): Void { + if ( not needRelayout) { + needRelayout = true; + FX.deferAction( function(): Void { + needRelayout = false; + computeLayoutDown(); + }); + } + } + + public override function create(): Node { + for ( dn in dragNodes) { + dn.size = dragNodeSize; + dn.dragAction = dragListener; + } + computeLayoutDown(); + Group { + content: [debugRect, border, dragNodes, item ]; + } + } + + public override function getPrefWidth(height: Number) : Number + { + -1 + } + + public override function getPrefHeight(width: Number) : Number + { + -1 + } + + protected function computeLayoutDown(): Void { + var itemWidth: Number = width - 2*margin; + var itemHeight: Number = height - 2*margin; + Container.layoutNode(item, margin, margin, itemWidth, itemHeight); + + var w2 = width / 2; + var h2 = height / 2; + var m2 = margin / 2; + border.x = 0; + border.y = 0; + border.translateX = m2; + border.translateY = m2; + border.width = width - margin; + border.height = height - margin; + + positionDragNode(n, w2, m2 ); + positionDragNode(ne, width-m2, m2 ); + positionDragNode(e, width-m2, h2 ); + positionDragNode(se, width-m2, height-m2 ); + positionDragNode(s, w2, height-m2 ); + positionDragNode(sw, m2, height-m2 ); + positionDragNode(w, m2, h2 ); + positionDragNode(nw, m2, m2 ); + } + + protected function positionDragNode( node: DragNode, x: Number, y: Number): Void { + node.x = x; + node.y = y; + } + + protected function computeLayoutUp(): Void { + var itemWidth: Number; + var itemHeight: Number; + + if ( item instanceof SwingComponent ) { + itemWidth = (item as SwingComponent).width; + itemHeight = (item as SwingComponent).height; + } + else if ( item instanceof Resizable ) { + itemWidth = (item as Resizable).width; + itemHeight = (item as Resizable).height; + } + + // Container.layoutNode(item, margin, margin, itemWidth, itemHeight); + border.width = itemWidth + margin*2; + border.height = itemHeight + margin*2 ; +// FX.println("computeLayout width={width}, height={height}, itemWidth={itemWidth}, itemHeight={itemHeight}, item.layout={item.layoutBounds}"); + } + + protected function positionBorder( x: Number, y: Number, w: Number, h: Number ): Void { + var x2 = Math.max(x, marginWidth ); + var y2 = Math.max(y, marginHeight); + var w2 = Math.max( Math.min(w, maximumWidth ), minimumWidth ); + var h2 = Math.max( Math.min(h, maximumHeight ), minimumHeight ); + this.layoutX = x2; + this.layoutY = y2; + this.width = w2; + this.height = h2; + } + + protected function dragListener( node: DragNode, deltaX: Number, deltaY: Number, e: MouseEvent): Void { + println("node.id={%4s node.id} deltaX={%7.3f deltaX}, deltaY={%7.3f deltaY}, e={e}"); + if ( node.id.equals("nw")) { + var xpos = this.layoutX + deltaX; + var ypos = this.layoutY + deltaY; + var newWidth = this.width + -deltaX; + var newHeight = this.height + -deltaY; + positionBorder( xpos, ypos, newWidth, newHeight ); + } + else if ( node.id.equals("n")) { + var ypos = this.layoutY + deltaY; + var newHeight = this.height + -deltaY; + positionBorder( layoutX, ypos, width, newHeight ); + } + else if ( node.id.equals("ne") or node.id.equals("e")) { + var newWidth = e.x; + positionBorder( layoutX, layoutY, newWidth, height ); + } + else if ( node.id.equals("se")) { + var newWidth = e.x; + var newHeight = e.y; + positionBorder( layoutX, layoutY, newWidth, newHeight ); + } + else if ( node.id.equals("s")) { + var newHeight = e.y; + positionBorder( layoutX, layoutY, width, newHeight ); + } + else if ( node.id.equals("sw")) { + var xpos = this.layoutX + deltaX; + var newWidth = this.width + -deltaX; + var newHeight = e.y; + positionBorder( xpos, layoutY, newWidth, newHeight ); + } + else if ( node.id.equals("w")) { + var xpos = this.layoutX + deltaX; + var newWidth = this.width + -deltaX; + positionBorder( xpos, layoutY, newWidth, height ); + } + } + +} + + +/** + * The rectangle + */ +protected class DragNode extends Rectangle { + + + /** The sixe of the square */ + public var size: Number on replace { + if ( isInitialized(size)) { + width = size; + height = size; + translateX = translateY = -size / 2; + // x = y = -size/2; + } + }; + + override var stroke = Color.BLACK; + override var strokeWidth = 1; + override var blocksMouse = true; + + + public var btnUpFill: Color = Color.LIGHTBLUE; + public var btnHoverFill: Color = Color.ORANGE; + public var btnDownFill: Color = Color.GREEN; + public var normalCursor: Cursor = Cursor.DEFAULT; + public var hoverCursor: Cursor = Cursor.DEFAULT; + + public var dragAction: function( node: DragNode, deltaX: Number, deltaY: Number, e:MouseEvent ): Void; + + var buttonDown: Boolean; + var startX: Number; + var startY: Number; + + override var onMousePressed = function( e: MouseEvent ):Void { + fill = btnDownFill; + buttonDown = true; + startX = e.x; + startY = e.y; + } + + override var onMouseReleased = function( e: MouseEvent ):Void { + fill = btnUpFill; + buttonDown = false; + } + + override var onMouseEntered = function( e: MouseEvent ):Void { + this.cursor = hoverCursor; + fill = if ( buttonDown) btnDownFill else btnHoverFill; + } + + override var onMouseExited = function( e: MouseEvent ):Void { + this.cursor = normalCursor; + fill = if ( buttonDown) btnDownFill else btnUpFill; + } + + override var onMouseDragged = function( e: MouseEvent ):Void { + if ( dragAction != null ) { + var deltaX = e.x - startX ; + var deltaY = e.y - startY ; + dragAction( this, deltaX, deltaY, e ); + } + + } + + postinit { + fill = btnUpFill; + } + +} + + +/** + * A main entry program for testing this component visually + */ +public function run( args: String[] ): Void { + var editor = TextEditor.create( Font{size: 22 name:"Courier New"}, + Color.BLUE, Color.RED, Color.BEIGE, function(): Void {} ); + (editor.node as SwingComponent).width = 400; + (editor.node as SwingComponent).height = 400; + + editor.setText("Noted Podcasts:-\n" + "* TEDTalks\n" + "* Buzz Out Loud\n" + "* The Buzz Report\n" + "* NPR: Wait Wait... Don't Tell Me! Podcast\n" + "* This American Life\n" + "* Stanford Entrepreneurial Thought Leaders\n" ); + + Stage { + title : "Testing DraggableLineBorder" + scene: Scene { + width: 800 + height: 600 + content: [ + DraggableLineBorder { + layoutX: 50 + layoutY: 50 + width: 400 + height: 400 + maximumWidth: 600 + maximumHeight: 600 + item: editor.node + } + ] + } + } +} diff --git a/src/zen/like/LineBorder.fx b/src/zen/like/LineBorder.fx new file mode 100644 index 0000000..80aef85 --- /dev/null +++ b/src/zen/like/LineBorder.fx @@ -0,0 +1,129 @@ +/* + * LineBorder.fx + * + * Created on 15-Mar-2010, 12:36:56 + */ + +package zen.like; + +import javafx.scene.CustomNode; +import javafx.scene.Node; +import javafx.scene.Group; +import javafx.stage.Stage; +import javafx.scene.Scene; +import javafx.scene.layout.Resizable; +import javafx.scene.layout.Container; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Font; +import javafx.ext.swing.SwingComponent; + +def STEP=10; + +/** + * Line border component + * @author Peter Pilgrim at the Java Posse Roundup 2010 + */ + +public class LineBorder extends CustomNode, Resizable { + + public var margin: Number = 10 on replace { + computeLayoutDown(); + }; + + public-init var item: Node; + + override var width on replace { + computeLayoutDown(); + } + override var height on replace { + computeLayoutDown(); + } + + public var borderStrokeColor: Color = Color.BLACK; + public var borderFillColor: Color = Color.TRANSPARENT; + public var borderWidth: Number = 2; + + + var border = Rectangle { + strokeWidth: bind borderWidth; + strokeDashOffset: 4 + strokeDashArray: [ 4, 8 ] + stroke: bind borderStrokeColor; + fill: bind borderFillColor; + }; + + public override function create(): Node { + Group { + content: [border, item ]; + } + } + + protected function computeLayoutDown(): Void { + border.width = width; + border.height = height; + var itemWidth: Number = width - 2*margin; + var itemHeight: Number = height - 2*margin; + Container.layoutNode(item, margin, margin, itemWidth, itemHeight); + } + + + protected function computeLayoutUp(): Void { + var itemWidth: Number; + var itemHeight: Number; + + if ( item instanceof SwingComponent ) { + itemWidth = (item as SwingComponent).width; + itemHeight = (item as SwingComponent).height; + } + else if ( item instanceof Resizable ) { + itemWidth = (item as Resizable).width; + itemHeight = (item as Resizable).height; + } + + // Container.layoutNode(item, margin, margin, itemWidth, itemHeight); + border.width = itemWidth + margin*2; + border.height = itemHeight + margin*2 ; +// FX.println("computeLayout width={width}, height={height}, itemWidth={itemWidth}, itemHeight={itemHeight}, item.layout={item.layoutBounds}"); + } + + + public override function getPrefWidth(height: Number) : Number + { + -1 + } + + public override function getPrefHeight(width: Number) : Number + { + -1 + } + + +} + +/** + * A main entry program for testing this component visually + */ +public function run( args: String[] ): Void { + var editor = TextEditor.create( Font{size: 32 name:"Courier New"}, + Color.BLUE, Color.RED, Color.BEIGE, function(): Void {} ); + (editor.node as SwingComponent).width = 400; + (editor.node as SwingComponent).height = 400; + + Stage { + title : "Testing LineBorder" + scene: Scene { + width: 800 + height: 600 + content: [ + LineBorder { + width: 400 + height: 400 + item: editor.node + } + ] + } + } +} + +// End. diff --git a/src/zen/like/MenuPanel.fx b/src/zen/like/MenuPanel.fx new file mode 100644 index 0000000..e12f4ca --- /dev/null +++ b/src/zen/like/MenuPanel.fx @@ -0,0 +1,88 @@ +/* + * MenuPanel.fx + * + * Created on Mar 15, 2010, 3:14:37 PM + */ + +package zen.like; +import javafx.scene.Group; +import javafx.scene.shape.Rectangle; +import javafx.scene.paint.Color; +import javafx.animation.Timeline; +import javafx.animation.KeyFrame; +import javafx.scene.layout.VBox; +import javafx.scene.control.Label; + +/** + * @author dick + */ + +public class MenuPanel extends Group { + + public var x: Number; + public var y: Number; + public var width: Number; + public var height: Number; + + override var opacity = 1.0; + override var onMouseEntered = function(e) { + Timeline { + repeatCount: 1 + keyFrames : [ + KeyFrame { + time : 0.5s + canSkip : true + values: opacity => 1 + } + ] + }.play(); + } + + override var onMouseExited = function(e) { + Timeline { + repeatCount: 1 + keyFrames : [ + KeyFrame { + time : 0.5s + canSkip : true + values: opacity => 0 + } + ] + }.play(); + } + + var rectangle = Rectangle { + fill: Color.WHITE + x: bind x + y: bind y + width: bind width + height: bind height + opacity: 0.5 + } + + public var saveButton: WorkMenuButton; + public var workButton: WorkMenuButton; + + def MARGIN=3; + + postinit { + content = [ + + rectangle, + VBox { + spacing: 5 + layoutX: bind x+MARGIN; + layoutY: bind y+MARGIN; + width: bind width-2*MARGIN; + height: bind height-2*MARGIN; + content: [ + workButton = WorkMenuButton{ content: "W" }, + saveButton = WorkMenuButton{ content: "S" }, + + ] + } + ] + } + + +} diff --git a/src/zen/like/TextEditor.fx b/src/zen/like/TextEditor.fx new file mode 100644 index 0000000..843a477 --- /dev/null +++ b/src/zen/like/TextEditor.fx @@ -0,0 +1,106 @@ +/* + * TextEditor.fx + * + * Created on Mar 15, 2010, 11:10:07 AM + */ + +package zen.like; + +import javafx.scene.Node; +import javax.swing.JScrollPane; +import javafx.ext.swing.SwingComponent; +import javax.swing.border.EmptyBorder; +import java.awt.Insets; +import javafx.scene.text.Font; +import javafx.scene.paint.Color; +import javax.swing.JTextPane; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.lang.StringBuilder; +import java.io.FileNotFoundException; +import zenwriterfx.Utilities; + +public class TextEditor { + public-read var node: Node; + public-read var textPane: JTextPane; + public var file: File; + public function save(): Void { + def s = textPane.getText(); + if (s != null) { + var output = + new OutputStreamWriter(new FileOutputStream("foo.txt"), "UTF-8"); + output.write(s.toString()); + output.close(); + } + } + + public function load(ignore: Boolean): Void { + try { + def input = new FileInputStream("foo.txt"); + def text = Utilities.read(input); + textPane.setText(text); + } catch (fnfe: FileNotFoundException) { + if (ignore) { + return; + } else { + throw fnfe; + } + } + } + + public function setText( content: String ): Void { + textPane.setText(content); + } + + public function getText(): String { + return textPane.getText(); + } + +} + +function awtToFx(font: javafx.scene.text.Font): java.awt.Font { + font.impl_getNativeFont() as java.awt.Font; +} + +function awtToFx(color: javafx.scene.paint.Color): java.awt.Color { + color.impl_getPlatformPaint() as java.awt.Color; +} + +public function create(font: Font, textColor: Color, selectionColor: Color, + selectionTextColor: Color, onKeyPressed: function(): Void): TextEditor { + var textPane = new AntiAliasedTextArea(); + + var scrollPane = new JScrollPane(textPane); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + var text: SwingComponent = SwingComponent.wrap(scrollPane); + textPane.setBackground(new java.awt.Color(0,0,0,0)); // 0 opacity => 100% transparent! + def awtTextColor = awtToFx(textColor); + textPane.setForeground(awtTextColor); + textPane.setCaretColor(awtTextColor); + textPane.setSelectionColor(awtToFx(selectionColor)); + textPane.setSelectedTextColor(awtToFx(selectionTextColor)); + + scrollPane.setOpaque(false); + scrollPane.setBorder(new EmptyBorder(new Insets(0,0,0,0))); + textPane.setFont(awtToFx(font)); + FX.deferAction(function() { // Ewwwww + textPane.requestFocus(); + }); + + def keyListener = KeyListener { onKeyPressed: onKeyPressed }; + textPane.addKeyListener(keyListener); + + TextEditor { node: text, textPane: textPane, file: new File("TheZenWriterFile.txt") } +} + +class KeyListener extends java.awt.event.KeyAdapter { + public-init var onKeyPressed: function(): Void; + override function keyPressed(e) { + onKeyPressed() + } +} diff --git a/src/zen/like/WorkMenuButton.fx b/src/zen/like/WorkMenuButton.fx new file mode 100644 index 0000000..697d8ce --- /dev/null +++ b/src/zen/like/WorkMenuButton.fx @@ -0,0 +1,68 @@ +/* + * WorkMenuButton.fx + * + * Created on 15-Mar-2010, 16:26:44 + */ + +package zen.like; + +import javafx.scene.Node; +import javafx.scene.text.*; +import javafx.stage.Stage; +import javafx.scene.Scene; +import javafx.scene.paint.Color; + +/** + * Working text node icon implementation + * @author Peter Pilgrim at the Java Posse Roundup 2010 + */ + +public class WorkMenuButton extends AbstractMenuButton { + + /** Text content */ + public var content: String = "W"; + + public override function createIconFaceNode(): Node { + Text { + // *PP* 15/03/2010 + // Need to talk to Amy Fowler. This code is contradictory to visual inspection. + // Trying to center the "W" in the middle of the circle. + // I would have thought it was width/2 height/2 in FX 1.3 (TextOrigin.CENTER) + translateX: bind width*0.25 + translateY: bind height*0.25 + font : Font { + size: 24 + } + textAlignment: TextAlignment.CENTER + textOrigin: TextOrigin.BASELINE + content: bind content; + } + } + +} + + +/** + * A main entry program for testing this component visually + */ +public function run( args: String[] ): Void { + Stage { + title : "Work Menu Button Helper" + scene: Scene { + width: 400 + height: 400 + fill: Color.web("#F0F0FF") + content: [ + WorkMenuButton { + layoutX: 150 layoutY: 150 + onAction: function(): Void { + println("******** Button Pressed *******"); + } + } + ] + + } + } + +} + diff --git a/src/zenwriterfx/Application.fx b/src/zenwriterfx/Application.fx new file mode 100644 index 0000000..9b01a84 --- /dev/null +++ b/src/zenwriterfx/Application.fx @@ -0,0 +1,17 @@ +/* + * Application.fx + * + * Created on Mar 15, 2010, 4:43:28 PM + */ + +package zenwriterfx; +import zen.like.TextEditor; + +public class Application { + public-init var editor: TextEditor; + + public function exit() { + editor.save(); + } +} + diff --git a/src/zenwriterfx/Main.fx b/src/zenwriterfx/Main.fx new file mode 100644 index 0000000..62461e8 --- /dev/null +++ b/src/zenwriterfx/Main.fx @@ -0,0 +1,134 @@ +/* + * Main.fx + * + * Created on Mar 15, 2010, 9:58:54 AM + */ +package zenwriterfx; + +import javafx.stage.Stage; +import javafx.scene.Scene; +import javafx.scene.image.ImageView; +import javafx.scene.image.Image; +import zen.like.TextEditor; +import javafx.ext.swing.SwingComponent; +import zen.like.MenuPanel; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import javafx.animation.Timeline; +import javafx.animation.KeyFrame; +import javafx.stage.Screen; +import zen.like.LineBorder; +import zen.like.DraggableLineBorder; + +public function run(args: String[]) { + def themeName = if (sizeof args == 0) Theme.DEFAULT else args[0]; + def theme = Theme.getTheme(themeName); + if (theme == null) { + println("No such theme: {themeName}"); + println("Available names: {Theme.getNames()}"); + FX.exit(); + } + + var scene: Scene; + def keyTyped = function(): Void { + theme.playClick(); + } + def editor = TextEditor.create(theme.font, theme.textColor, theme.selectionColor, theme.selectionTextColor, keyTyped); + def editorNode: SwingComponent = editor.node as SwingComponent; + def lineBorder: DraggableLineBorder = DraggableLineBorder{ item: editorNode }; + editor.load(true); + + def menuPanel = MenuPanel {}; + + editorNode.focusTraversable = true; + + var width: Number = bind stage.width on replace { + lineBorder.width = width * (theme.endX - theme.beginX); + lineBorder.translateX = width * theme.beginX; + lineBorder.maximumWidth = stage.width - 20; + menuPanel.x = width * theme.panelX; + menuPanel.width = width * theme.panelWidth; + }; + var height: Number = bind stage.height on replace { + lineBorder.height = height * (theme.endY - theme.beginY); + lineBorder.translateY = height * theme.beginY; + lineBorder.maximumHeight = stage.height - 20; + menuPanel.y = height * theme.panelY; + menuPanel.height = height * theme.panelHeight; + }; + + if (theme.backgroundAudio != null) { + // Start a timeline to initialize audio AFTER everything + // else has come up + Timeline { + repeatCount: 1 + keyFrames: KeyFrame { + time: 0.3s + action: function() { + MediaPlayer { + volume: theme.backgroundAudioVolume + media: Media { + source: Utilities.makeLocal(theme.backgroundAudio); + } + autoPlay: true + repeatCount: MediaPlayer.REPEAT_FOREVER + onError: function(e) { + println(e); + } + } + } + } + }.play(); + } + + def bounds = Screen.primary.bounds; + def imageView = + ImageView { + opacity: 0 + fitWidth: bind width + fitHeight: bind height + } + + Timeline { + repeatCount: 1 + keyFrames: [ + KeyFrame { + time: 0.1s + action: function() { + imageView.image = Image { + backgroundLoading: false + url: theme.backgroundImage + } + + Timeline { + repeatCount: 1 + keyFrames: [ + KeyFrame { + time: 0.8s + values: imageView.opacity => theme.opacity + } + ] + }.play(); + } + } + ] + }.play(); + + def stage: Stage = Stage { + fullScreen: true + title: "ZenWriterFX" + width: bounds.width + height: bounds.height + scene: scene = Scene { + content: [ + imageView, + lineBorder, + menuPanel + ] + fill: theme.fill + } + } + + editorNode.requestFocus(); + Utilities.addShutdown(Application { editor: editor }); +} diff --git a/src/zenwriterfx/Theme.fx b/src/zenwriterfx/Theme.fx new file mode 100644 index 0000000..01e48bd --- /dev/null +++ b/src/zenwriterfx/Theme.fx @@ -0,0 +1,122 @@ +/* + * Theme.fx + * + * Created on Mar 15, 2010, 12:35:14 PM + */ + +package zenwriterfx; + +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.scene.paint.Color; +import javafx.scene.media.MediaPlayer; +import javafx.scene.media.Media; +import java.util.Random; + +public class Theme { + public-init var name: String; + public-init var backgroundImage: String; + public-init var backgroundAudio: String; + public-init var backgroundAudioVolume = 1.0; + public-init var beginX = 0.1; + public-init var beginY = 0.1; + public-init var endX = 0.7; + public-init var endY = 0.9; + public-init var panelX = 0.75; + public-init var panelY = 0.1; + public-init var panelWidth = 0.15; + public-init var panelHeight = 0.6; + public-init var fill: Paint = Color.WHITE; + public-init var textColor = Color.BLACK; + public-init var selectionTextColor = Color.WHITE; + public-init var selectionColor = Color.rgb(255, 255, 255, 0.5); + public-init var opacity = 0.3; + public-init var font: Font; + public-init var clickSound: String; + + public def clickMedia = { + def local = Utilities.makeLocal(clickSound); + if (local != null) { + Media { + onError: function(error) { + println("{error}"); + } + source: local + } + } else { + null + } + } + + var mediaPlayer = MediaPlayer { + media: clickMedia + } + + public function playClick() { + if (clickMedia != null) { + mediaPlayer.currentTime = 0s; + mediaPlayer.volume = new Random().nextFloat()*0.5 + 0.5; + mediaPlayer.play(); + } + } +} + +public function getTheme(name: String) { + for (theme in themes) { + if (theme.name == name) { + return theme; + } + } + + null +} + +public def DEFAULT = "Default"; + +public function getNames(): String[] { + for (theme in themes) { + "{theme.name}, " + } +} + + +def themes: Theme[] = [ + Theme { + name: DEFAULT + opacity: 0.5 + backgroundImage: "{__DIR__}images/backgrounds/WriterZen-BG038.JPG" + backgroundAudio: "{__DIR__}sounds/background/OceanWave.wav" + backgroundAudioVolume: 0.3 + font: Font.font("Helvetica", 24) + clickSound: "{__DIR__}sounds/keyclick/typewriter-key.wav" + }, + Theme { + name: "Dick" + backgroundImage: "{__DIR__}images/backgrounds/WriterZen-BG003.JPG" + font: Font.font("Rufscript", 24) + }, + Theme { + name: "netbeans" + opacity: 0.8 + backgroundImage: "{__DIR__}images/backgrounds/netbeans.png" + font: Font.font("Courier", 24) + clickSound: "{__DIR__}sounds/keyclick/typewriter-key.wav" + beginX: 0.27 + beginY: 0.2 + endX: 0.9 + endY: 0.695 + panelX: 0.9 + panelY: 0.2 + panelWidth: 0.1 + panelHeight: 0.6 + }, + Theme { + name: "Ugly" + backgroundImage: "{__DIR__}images/backgrounds/WriterZen-BG002.JPG" + font: Font.font("American Typewriter", 20) + textColor: Color.YELLOW + selectionColor: Color.RED + selectionTextColor: Color.GREEN + fill: Color.PURPLE + } +]; diff --git a/src/zenwriterfx/Utilities.java b/src/zenwriterfx/Utilities.java new file mode 100644 index 0000000..a7ef1b9 --- /dev/null +++ b/src/zenwriterfx/Utilities.java @@ -0,0 +1,101 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package zenwriterfx; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Utilities { + public static String makeLocal(String url) { + try { + if (url == null || url.length() == 0) { + return null; + } + String name = url.substring(url.lastIndexOf('/')+1); + File tmpdir = new File(java.lang.System.getProperty("java.io.tmpdir")); + File localFile = new File(tmpdir, name); + if (localFile.exists()) { + return localFile.toURI().toURL().toExternalForm(); + } + + // Copy resource locally + URL u = new URL(url); + FileOutputStream writer = new FileOutputStream(localFile); + InputStream input = u.openStream(); + while (true) { + int c = input.read(); + if (c == -1) { + break; + } + writer.write((char)c); + } + + writer.close(); + + + return localFile.toURI().toURL().toExternalForm(); + } catch (Exception e) { + return null; + } + } + + public static String read(InputStream inputStream) throws IOException { + BufferedReader input = new BufferedReader(new InputStreamReader(inputStream)); + try { + StringBuilder sb = new StringBuilder(); + + while (true) { + int c = input.read(); + if (c == -1) { + break; + } + sb.append((char)c); + } + input.close(); + input = null; + return sb.toString(); + } finally { + if (input != null) { + input.close(); + } + } + } + + + public static void addShutdown(final Object instance) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + Class cls = Class.forName("zenwriterfx.Application"); + Method method = cls.getMethod("exit", (Class[])null); + method.invoke(instance, (Object[])null); + } catch (IllegalAccessException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalArgumentException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } catch (InvocationTargetException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } catch (NoSuchMethodException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotFoundException ex) { + Logger.getLogger(Utilities.class.getName()).log(Level.SEVERE, null, ex); + } + } + }); + } +} diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG012.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG012.JPG new file mode 100644 index 0000000..65f7049 Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG012.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG023.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG023.JPG new file mode 100644 index 0000000..861663d Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG023.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG038.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG038.JPG new file mode 100644 index 0000000..8d2f32d Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG038.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG041.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG041.JPG new file mode 100644 index 0000000..b3af6ff Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG041.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG107.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG107.JPG new file mode 100644 index 0000000..c768e3a Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG107.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG110.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG110.JPG new file mode 100644 index 0000000..13b81a5 Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG110.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/WriterZen-BG126.JPG b/src/zenwriterfx/images/backgrounds/WriterZen-BG126.JPG new file mode 100644 index 0000000..84dfd23 Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/WriterZen-BG126.JPG differ diff --git a/src/zenwriterfx/images/backgrounds/netbeans.png b/src/zenwriterfx/images/backgrounds/netbeans.png new file mode 100644 index 0000000..df0dee0 Binary files /dev/null and b/src/zenwriterfx/images/backgrounds/netbeans.png differ diff --git a/src/zenwriterfx/sounds/background/OceanWave.wav b/src/zenwriterfx/sounds/background/OceanWave.wav new file mode 100644 index 0000000..a312975 Binary files /dev/null and b/src/zenwriterfx/sounds/background/OceanWave.wav differ diff --git a/src/zenwriterfx/sounds/keyclick/typewriter-key.wav b/src/zenwriterfx/sounds/keyclick/typewriter-key.wav new file mode 100644 index 0000000..c3fb1e7 Binary files /dev/null and b/src/zenwriterfx/sounds/keyclick/typewriter-key.wav differ