Added NotesDialog MVC. Wired window movement. Added GUIUtil
This commit is contained in:
parent
5000d266fe
commit
02fc6b5bb7
@ -0,0 +1,3 @@
|
|||||||
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
def emptyAction = action(name: 'Empty Action')
|
@ -9,6 +9,14 @@ application {
|
|||||||
//frameClass = 'javax.swing.JFrame'
|
//frameClass = 'javax.swing.JFrame'
|
||||||
}
|
}
|
||||||
mvcGroups {
|
mvcGroups {
|
||||||
|
// MVC Group for "com.jdbernard.timestamper.NotesDialog"
|
||||||
|
'NotesDialog' {
|
||||||
|
actions = 'com.jdbernard.timestamper.NotesDialogActions'
|
||||||
|
model = 'com.jdbernard.timestamper.NotesDialogModel'
|
||||||
|
controller = 'com.jdbernard.timestamper.NotesDialogController'
|
||||||
|
view = 'com.jdbernard.timestamper.NotesDialogView'
|
||||||
|
}
|
||||||
|
|
||||||
// MVC Group for "com.jdbernard.timestamper.TimeStamperMain"
|
// MVC Group for "com.jdbernard.timestamper.TimeStamperMain"
|
||||||
'TimeStamperMain' {
|
'TimeStamperMain' {
|
||||||
actions = 'com.jdbernard.timestamper.TimeStamperMainActions'
|
actions = 'com.jdbernard.timestamper.TimeStamperMainActions'
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
import java.awt.Rectangle
|
||||||
|
import java.awt.Toolkit
|
||||||
|
|
||||||
|
class NotesDialogController {
|
||||||
|
// these will be injected by Griffon
|
||||||
|
def model
|
||||||
|
def view
|
||||||
|
|
||||||
|
|
||||||
|
void mvcGroupInit(Map args) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Point mousePressRelativeToDialog
|
||||||
|
|
||||||
|
def mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
||||||
|
|
||||||
|
def mouseDragged = { evt ->
|
||||||
|
GUIUtil.componentDragged(view.notesDialog, evt,
|
||||||
|
mousePressRelativeToDialog,
|
||||||
|
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
||||||
|
app.views.TimeStamperMain.frame.bounds)
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,24 @@
|
|||||||
package com.jdbernard.timestamper
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
import java.awt.Rectangle
|
||||||
|
import java.awt.Toolkit
|
||||||
|
import java.util.Timer
|
||||||
|
|
||||||
class TimeStamperMainController {
|
class TimeStamperMainController {
|
||||||
// these will be injected by Griffon
|
// these will be injected by Griffon
|
||||||
def model
|
def model
|
||||||
def view
|
def view
|
||||||
|
|
||||||
|
Timer updateTimer
|
||||||
|
|
||||||
|
Point mousePressRelativeToFrame
|
||||||
|
|
||||||
void mvcGroupInit(Map args) {
|
void mvcGroupInit(Map args) {
|
||||||
// this method is called after model and view are injected
|
def notes = buildMVCGroup('NotesDialog')
|
||||||
|
view.notesDialog = notes.view.notesDialog
|
||||||
|
|
||||||
|
updateTimer
|
||||||
}
|
}
|
||||||
|
|
||||||
def exitGracefully = { evt = null ->
|
def exitGracefully = { evt = null ->
|
||||||
@ -16,4 +28,22 @@ class TimeStamperMainController {
|
|||||||
def showToolsMenu = { evt = null ->
|
def showToolsMenu = { evt = null ->
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def showNotes = { evt = null ->
|
||||||
|
view.notesDialog.visible = view.notesVisibleButton.selected
|
||||||
|
}
|
||||||
|
|
||||||
|
def showPunchcard = { evt = null ->
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def mousePressed = { evt = null ->
|
||||||
|
mousePressRelativeToFrame = evt?.point
|
||||||
|
}
|
||||||
|
|
||||||
|
def mouseDragged = { evt = null ->
|
||||||
|
GUIUtil.componentDragged(view.frame, evt, mousePressRelativeToFrame,
|
||||||
|
new Rectangle(Toolkit.defaultToolkit.screenSize))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import groovy.beans.Bindable
|
||||||
|
|
||||||
|
class NotesDialogModel {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import java.awt.Color
|
||||||
|
import javax.swing.BoxLayout
|
||||||
|
import net.miginfocom.swing.MigLayout
|
||||||
|
|
||||||
|
notesDialog = dialog(
|
||||||
|
title: 'Notes',
|
||||||
|
modal: false,
|
||||||
|
undecorated: true,
|
||||||
|
minimumSize: [325, 200],
|
||||||
|
iconImage: imageIcon('/16-em-pencil.png').image,
|
||||||
|
iconImages: [imageIcon('/16-em-pencil.png').image]
|
||||||
|
) {
|
||||||
|
|
||||||
|
panel(
|
||||||
|
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
|
||||||
|
mousePressed: controller.&mousePressed,
|
||||||
|
mouseDragged: controller.&mouseDragged,
|
||||||
|
layout: new MigLayout('insets 5 5 5 5, fill')
|
||||||
|
) {
|
||||||
|
scrollPane(constraints: 'growx, growy') {
|
||||||
|
notesTextArea = textArea(lineWrap: true, columns: 20, rows: 5,
|
||||||
|
wrapStyleWord: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@ import java.awt.Font
|
|||||||
import javax.swing.BoxLayout
|
import javax.swing.BoxLayout
|
||||||
import net.miginfocom.swing.MigLayout
|
import net.miginfocom.swing.MigLayout
|
||||||
|
|
||||||
application(title:'TimeStamper',
|
frame = application(title:'TimeStamper',
|
||||||
//size:[320,480],
|
//size:[320,480],
|
||||||
pack:true,
|
pack:true,
|
||||||
//location:[50,50],
|
//location:[50,50],
|
||||||
@ -17,7 +17,9 @@ application(title:'TimeStamper',
|
|||||||
) {
|
) {
|
||||||
panel(
|
panel(
|
||||||
border:lineBorder(color:Color.BLACK, thickness:1, parent:true),
|
border:lineBorder(color:Color.BLACK, thickness:1, parent:true),
|
||||||
layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]')
|
layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]'),
|
||||||
|
mousePressed: controller.&mousePressed,
|
||||||
|
mouseDragged: controller.&mouseDragged
|
||||||
) {
|
) {
|
||||||
def mainFont = new Font(Font.SANS_SERIF, Font.BOLD, 12)
|
def mainFont = new Font(Font.SANS_SERIF, Font.BOLD, 12)
|
||||||
def timeFont = new Font(Font.SANS_SERIF, Font.BOLD, 14)
|
def timeFont = new Font(Font.SANS_SERIF, Font.BOLD, 14)
|
||||||
@ -45,10 +47,12 @@ application(title:'TimeStamper',
|
|||||||
|
|
||||||
panel(constraints: 'alignx leading, aligny top, gapright 5px, wrap') {
|
panel(constraints: 'alignx leading, aligny top, gapright 5px, wrap') {
|
||||||
boxLayout(axis: BoxLayout.X_AXIS)
|
boxLayout(axis: BoxLayout.X_AXIS)
|
||||||
toggleButton(showNotesAction, icon: imageIcon('/16-em-pencil.png'),
|
notesVisibleButton = toggleButton(showNotesAction, icon: imageIcon('/16-em-pencil.png'),
|
||||||
|
hideActionText: true,
|
||||||
border: emptyBorder(4))
|
border: emptyBorder(4))
|
||||||
toggleButton(showPunchcardAction,
|
punchcardVisibleButton = toggleButton(showPunchcardAction,
|
||||||
icon: imageIcon('/16-file-archive.png'),
|
icon: imageIcon('/16-file-archive.png'),
|
||||||
|
hideActionText: true,
|
||||||
border: emptyBorder(4))
|
border: emptyBorder(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
src/main/com/jdbernard/timestamper/GUIUtil.groovy
Normal file
91
src/main/com/jdbernard/timestamper/GUIUtil.groovy
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
import java.awt.Rectangle
|
||||||
|
import java.awt.Toolkit
|
||||||
|
import java.awt.event.MouseEvent
|
||||||
|
|
||||||
|
public class GUIUtil {
|
||||||
|
|
||||||
|
static Point calculateWindowMovement(Point currentMousePoint,
|
||||||
|
Point mousePressRelativeToWindow, Rectangle windowBounds,
|
||||||
|
Rectangle... snapBoxes) {
|
||||||
|
|
||||||
|
// this is the point we will compute as the new upper left
|
||||||
|
// coordinate of the frame. It needs to be translated some to account
|
||||||
|
// for the fact that the user can press the mouse anywhere on the
|
||||||
|
// main panel.
|
||||||
|
Point currentWindowPoint = (Point) currentMousePoint.clone();
|
||||||
|
// find out where the new point should be, ignoreing screen bounds
|
||||||
|
currentWindowPoint.translate((int) -mousePressRelativeToWindow.x,
|
||||||
|
(int) -mousePressRelativeToWindow.y);
|
||||||
|
|
||||||
|
Point finalWindowPoint = (Point) currentWindowPoint.clone();
|
||||||
|
|
||||||
|
// snap tests. In the event of a conflict in snaps positions, the
|
||||||
|
// last snap wins
|
||||||
|
int wUp = windowBounds.y;
|
||||||
|
int wDown = windowBounds.y + windowBounds.height;
|
||||||
|
int wLeft = windowBounds.x;
|
||||||
|
int wRight = windowBounds.x + windowBounds.width;
|
||||||
|
|
||||||
|
// currentTaskLabel.setText("U:" + wUp + " D:" + wDown + " L:" + wLeft
|
||||||
|
// + " R:" + wRight);
|
||||||
|
|
||||||
|
for (Rectangle r : snapBoxes) {
|
||||||
|
int rUp = r.y;
|
||||||
|
int rDown = r.y + r.height;
|
||||||
|
int rLeft = r.x;
|
||||||
|
int rRight = r.x + r.width;
|
||||||
|
|
||||||
|
// check to see if the window is near any of the snap boundaries
|
||||||
|
// if it is, 'snap' the final point to that boundary.
|
||||||
|
if (Math.abs(rUp - wUp) < 20) // top of window to top of rect
|
||||||
|
finalWindowPoint.y = rUp;
|
||||||
|
else if (Math.abs(rUp - wDown) < 20) // bot of w to top of r
|
||||||
|
finalWindowPoint.y = rUp - windowBounds.height;
|
||||||
|
else if (Math.abs(rDown - wUp) < 20) // top of w to bot of r
|
||||||
|
finalWindowPoint.y = rDown;
|
||||||
|
else if (Math.abs(rDown - wDown) < 20) // bot of w to bot of r
|
||||||
|
finalWindowPoint.y = rDown - windowBounds.height;
|
||||||
|
|
||||||
|
if (Math.abs(rLeft - wLeft) < 20) // left of w to left of r
|
||||||
|
finalWindowPoint.x = rLeft;
|
||||||
|
else if (Math.abs(rLeft - wRight) < 20) // right of w to left of r
|
||||||
|
finalWindowPoint.x = rLeft - windowBounds.width;
|
||||||
|
else if (Math.abs(rRight - wLeft) < 20) // left of w to right of r
|
||||||
|
finalWindowPoint.x = rRight;
|
||||||
|
else if (Math.abs(rRight - wRight) < 20) // right of w to right of r
|
||||||
|
finalWindowPoint.x = rRight - windowBounds.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this point represents a backwards version of the initial calculation
|
||||||
|
// to find the finalPoint. It says, based on the current final point,
|
||||||
|
// assume I moved the frame to that point. Where, relative to that point
|
||||||
|
// should the mouse be, based on how far it was relative to the point
|
||||||
|
// when the user pressed it.
|
||||||
|
Point whereMouseShouldBe = (Point) finalWindowPoint.clone();
|
||||||
|
whereMouseShouldBe.translate((int) mousePressRelativeToWindow.x,
|
||||||
|
(int) mousePressRelativeToWindow.y);
|
||||||
|
|
||||||
|
// if the actual mouse location is different from the expected location,
|
||||||
|
// then we know that the snapping behaviour has altered the frames new
|
||||||
|
// placement. If this alteration is too large (30 px apart in this case)
|
||||||
|
// then we know the user is trying to pull the frame out of its snapped
|
||||||
|
// position. In this case, we want to ignore the snap calculations and
|
||||||
|
// base the new frame location entirely on the current mouse location
|
||||||
|
if (whereMouseShouldBe.distance(currentMousePoint) > 30) {
|
||||||
|
finalWindowPoint = (Point) currentMousePoint.clone();
|
||||||
|
finalWindowPoint.translate((int) -mousePressRelativeToWindow.x,
|
||||||
|
(int) -mousePressRelativeToWindow.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalWindowPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
def static componentDragged(frame, MouseEvent evt,
|
||||||
|
Point mousePressRelativeToFrame, Rectangle... snapBoxes) {
|
||||||
|
frame.location = calculateWindowMovement(evt.getLocationOnScreen(),
|
||||||
|
mousePressRelativeToFrame, frame.bounds, snapBoxes)
|
||||||
|
}
|
||||||
|
}
|
10
test/integration/NotesDialogTests.groovy
Normal file
10
test/integration/NotesDialogTests.groovy
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import griffon.util.IGriffonApplication
|
||||||
|
|
||||||
|
class NotesDialogTests extends GroovyTestCase {
|
||||||
|
|
||||||
|
IGriffonApplication app
|
||||||
|
|
||||||
|
void testSomething() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user