Friday, 27 July 2012
Losing the Swing
The approach to implementing grace notes with no inheritance from Swing has proved it’s possible to code the widgets without needing them to be based on JComponent. There is a bug though, to do with scaling and where the note draws itself relative to the grace note. This is probably, fundamentally down to mixing two different approaches, at least that’s what I thought….
One 12 hour flight later, it’s all fixed. And we now have a toolbar so starting to make it easier to use the beast! Just got to build out the toolbar for inserting notes, gracenotes, adding ties and ligatures.
The JDrumNote class extends JComponent, I’m mixing the use of integers for x and y co-ordinates at that level, whereas greater precision is being used in the JGraceNote derived classes.
Flush with the non-Swing dependency in JGraceNote, it’s time to re-examine the reasons for using JComponent as the base for JStaffElement, from which JDrumNote is descended.
Java Drag and Drop (DND) was the principle reason for staying with Swing, that plus my total inexperience in writing anything as complex as this before. DND has proven itself to be so limited in capability when combined with AffineTransform use for scaling, and it’s implementation is different on each platform – on a Mac you automagically get a view of the dragged image as it’s moved around, however on Windows and Linux you don’t. Maybe I need to check SE 7 to see if any of this has changed recently, and once again my lack of knowledge is making decisions I can’t go back from.
Bottom line is there’s no DND capability built in to the JStaffElementSelection object anyway, so we can’t leverage DND. The thinking was DND would be used to communicate externally to the program, e.g. if there’s another copy running to move data between them – can still use copy and paste – but there’s no DND. That is a functionality problem I’ll have to fix at some point. It’s not going to be now, the complexity of weaving that in while I bring the core musical notation online is holding me back.
Removing the DND consideration as a constraint, time to go see if JStaffElement can live without JComponent!
While getting ready to start this though, I had a thought – I hadn’t actually tested moving a whole staff area around with any grace notes in it. Testing this resulted in a stack trace telling me I’ve implemented the grace note hierarchy without making the objects serializable. This has broken the ability to use DND to move the staff area around. Implementing Serializable on JGraceNote fixes that, as that abstract class is the basis of all grace notes.
Now we’re back in a known position but while testing above using a JFlam derived grace note, I noticed that the bug that started this wasn’t evident. Testing using both a JFlam and a JDrag the behaviour didn’t seem predictable, in fact I could tell it to zoom again to the same size and it would fix the alignment of the JDrag. All the time the JFlam behaved itself. The original diagnosis that the issue is embedded in integer rounding was perhaps me wanting it believe that, knowing I have to tackle the precision issue in JStaffElement – wrong conclusion jumped to as a result.
Now the issue appears to be something to do with scaling and location setting. Choosing Zoom 150% shows the issue, choosing it again fixes it. Repeatedly choosing Zoom150 after that changes nothing. Choosing Zoom100 has the note drawn too far away from the grace note. Choosing it again fixes it. Testing through all the zoom levels shows a consistent pattern, it’s drawn wrong the first time, but selecting the same zoom level for a second time fixes the problem. And throughout the JFlam isn’t affected. So there’s a problem with the JDrag gracenote, some debugging reveals the ligature that joins the notes in a drag isn’t being rescaled when we calculate the width, something’s doing it after we’ve returned it, which is why a second scaling returns the right answer.
More debugging reveals the correct ligature length is only calculated when setLocation is called. Is this bug happening because the underlying grace notes haven’t had their location set before we try to subtract the last one’s x from the first one’s? If so why does it have an x location anyway? It has one because it’s the stem x, not note head and that’s calculated from the note head width plus whatever the grace note x is, which is clearly zero at this point, meaning their location hasn’t been set.
Somehow the app is saying hey the scale has changed, and that’s being propagated through the objects before the resulting location change is propagated. Paint() then happens. Next paint doesn’t fix it as we’ve not gone through a scale change which is what would logically change the length of a grace note.
Its almost like scale change and location setting should be atomic, what is causing this sequence of events! And why isn’t this a problem for flams as they’re the exact same code structure.
Newsflash, this is happening for flams as well, it’s just imperceptible until zoomed right in. All starting to get consistent now, so we can be sure of the diagnosis. Switching to the simpler flam structure to continue researching why this order of events is happening and why we’re getting these consequences.
Oh dear, it seems we don’t have consistency. The width of the flam is determined by the offset of the X coord of it’s strike, that offset is being scaled correctly.
I thought it would be a quick fix by just setting locations of the notes as we cycled through them to tell them their scale, but we need our inter gracenote scale calculated first, so some code order juggling was needed to0.
Complex little bug sorted. I can now implement the other multi-grace note rudiments following the same pattern.
The bad news I found some bug in JDrumNote that’s causing a miniscule movement of the note on refresh of scale, thought maybe it’s a similar coding error. Also discovered that when creating a new staff area, it’s not respecting the current zoom factor in it’s drawing, always draws as 0 zoom, hey ho.