Last modified 10 years ago Last modified on 06/25/09 18:12:37

Error: Macro BackLinksMenu(None) failed
compressed data is corrupt

Error: Macro TicketQuery(summary=FRAME_ROTATION_R1, format=table, col=summary|owner|status|type|component|priority|effort|importance, rows=description|analysis_owners|analysis_reviewers|analysis_score|design_owners|design_reviewers|design_score|implementation_owners|implementation_reviewers|implementation_score|test_owners|test_reviewers|test_score|) failed
current transaction is aborted, commands ignored until end of transaction block



Update the frame rotation user interface to support dragging of a halo to rotate the frame. Remove the discreet rotation buttons from the halo menu and remove the hud. Rotation will be around the topLeft corner of the frame for this task revision.

Task requirements

  • Reduce the rotation halo menu to one button
  • Change the icon of the halo rotation button to indicate it can be dragged
  • Rotate around the topLeft corner of the frame (ie 0,0, so later when the coordinates change, the rotation works as expected)
  • Rotation center, halo button and mouse should be on the same line, when the user drags the halo button.
    • in the diagram below the dark rectangle represents single frame, the gray one is the halo button. And the rotation point is the one that the frame is rotates around. The rotation point will stay consistent no meter the rotation of the frame.

  • The halo button won't be rotated.
  • Make sure the halo button moves with the frame. Currently halos lay out around the unrotated bounding box enclosing the rotated frame
  • Position the center of the halo button at the bottom right corner of the frame, along a vector that extends from the top left corner to the bottom right, offset from the outside of the frame by 15,15 pixels (hard coded, changeable in order to avoid overlapping of halo buttons )
    • In the diagram below the larger rectangle is a frame and the smaller one is the halo button. The red line is the vector mentioned above.


  • When multiple frames are selected
    • The initial position of the halo button is equal by degrees to the first selected frame. (If for example the first selected frame has rotation 45 degree then the halo button is moved 45 degrees from the center of the selection rectangle)
    • The rotation point is at the top left corner.
    • Again during dragging the rotation point, the halo button and the mouse are on the same line.
      • In the diagram below the rectangles with numbers 1,2 and 3 are frames and the numbers represent the order of selection.
      • The first selected rectangle is with 45 degree rotation.
      • The rectangle that contains the 3 frames represent the selection rectangle.
      • The small grey rectangle at the bottom represents the position of the halo button if the rotation of the first selected frame is 0 degrees.
      • The small grey rectangle to the right of the selection represents the initial location of the halo if the rotation of the first selected frame is 45 degrees. The halo button is positioned here because it is 45 degrees from the bottom right of the selection rectangle, to match the rotation of the first selected frame.
      • Rotation point remains the same, the top left of the selection rectangle

  • However this is not the final analysis for multiple rotation, seence it won't be implemented in this revision, for the next one we could discuss this again

Task result

The result of this task is code

Implementation idea

  • Model the dragging after the frame move halo button pattern

How to demo

  • Run the application
  • Create a new book
  • Insert frame and rotate it
  • Insert few more frames and try to rotate each one individually


The design for this task is broken into the following categories:

  • Removing the rotate right and rotate left buttons from FrameRotateHaloMenu
  • Fixing the rotation properties dialog to rotate properly
  • Positioning the rotation halo menu properly
  • Writing a new class to handle both showing the rotation properties hud, and have it be draggable to rotate the frame

Due to time boxing, this task does not implement the optional rotation of multiple selected objects.

The following classes were modified:

  • FrameRotateHaloMenu
  • FrameRotationPropertiesHud
  • FrameRotateRightHaloButton (Removed from the menu, but fixed to ensure it would work should it be used at a later point in time)
  • FrameRotateLeftHaloButton (Removed from the menu, but fixed to ensure it would work should it be used at a later point in time)
  • FrameRotateLogic
  • AppHaloUtil
  • HaloMenu
  • HudHaloButton
  • MouseCapture

The follow classes were added:

  • HudHalo - An interface implemented by HudHaloButton and FrameDragRotatePropertiesHaloButton (more on this later)
  • FrameDragRotatePropertiesHaloButton


This class is responsible for defining the rotation center and rotation angle. It was determined during design that this hud had been eliminated in the analysis of this task and needed to be added back. This class was not updated during the rotation improvements of FRAME_SIZE_R1 and thus needed fixing. The FRAME_SIZE_R1 fixes added a EventR3 for ROTATE, but this event handled rotation by an incremental amount, whereas the rotation properties hud supplies an absolute rotation amount.

So, the ROTATE enum was renamed to ROTATE_BY and a new enum, ROTATE_TO was added to FrameRotateLogic.

This class was changed to use the new EventR3, ROTATE_TO.

This class also had its parent changed to FrameDragRotatePropertiesHaloButton

FrameRotateRightHaloButton / FrameRotateRightHaloButton

These classes were removed from FrameRotateHaloMenu, but they were updated to use the new ROTATE_BY EventR3, just in case this code is ressurected for use later


This class now implements ROTATE_TO. This method has to back out the existing rotation before it can apply the new rotation, or the frame will "walk" across the page, because all frame rotation is based around the content location now.


A helper method, getFirstFrameView, was added to get the first frame in the selection


The computeLocation method was changed to a fairly complex bit of code. First, we have to calculate a line from the top left of the frame to the bottom right. We then extend this line by HALO_OFFSET, a static final value, to determine where the halo menu should be centered. We then calculate the new endpoint of the line and have a haloMenuCenter.

This new center is in unrotated frame coodinates though, so we create a matrix rotated around the frame's content location to find the frameRotationCenter.

Next we create a matrix to rotate a point around the frameRotationCenter by the frame's current rotation value, and transform our haloMenuCenter.

Next, we use scene helpers to get the scene's effective transform and transform our haloMenuCenter by that. This is done so we zoom properly.

Next, we offset the haloMenuCenter so the halo menu will be centered on the proper point.

Finally, we convert the coordinates from scene to swing coordinates. The halo menu is now properly positioned for a rotated and scaled frame.


FrameDragRotatePropertiesHaloButton is the class that handles showing the properties hud and rotating the frame when drug around the rotation center. It was discovered that the existing classes, MoveHaloButton and HaloHudButton were not designed to be used together. After some discussion, it was decided, in order to finish the task on time, to create FrameDragRotatePropertiesHaloButton and have it subclass from MoveHaloButton.

Then, the two methods from HaloHudButton, hud() and computeHud() would be copied into this class, to save time until we refactor the other halo buttons. This allows FrameDragRotatePropertiesHaloButton to both show the properties hud when single clicked, and to rotate the frame when drug.

However, the properties hud would not show, because HaloMenu checks for (b instanceOf HudHaloButton) in two places. Not wanting to break anything, but also finish the task, a new interface was implemented, HudHalo, with the single method hud().

Both HudHaloButton and FrameDragRotatePropertiesHaloButton implement HudHalo, and HaloMenu now checks (b instanceof HudHalo) for its sanity checks. This factors out the implemention from the intention of the class check.

FrameDragRotatePropertiesHaloButton uses the same pattern as FrameMoveHaloButton. It calculates out the angle between the rotationCenter, the click point and the current mouse point. It then uses this to create a theta delta which is then applied to the frame via the ROTATE_BY EventR3.


MouseCapture was updated slightly to record the original click location and the current click location. A new method, hasMoved(), was added that returns TRUE if the mouse has moved at all during the life of this MouseCapture instance, and false if it has not.


Tried to model the unit test after FRAME_SIZE_R1's unit test, but could not ever get it to run and pass. Because the code uses the halo properties to determine the rotation center, etc. determined how to unit test this has been difficult.


Implemented as designed



[3741] has fix for unit testing, and a fix for FRAME_SIZE_R1 unit test FrameResizeTest from deni


(Place the testing results here.)


Rotating Selection

We need to think about what rotation means for 3 selected frames, where does the halo go, where doe the rotation center, on the temporary group or on each frame, each rotating potentially differently (one topLeft, one center, one bottomRight?) I checked out pages, and while they do not have an onscreen rotation widget (it is in a palette), it sets the rotation of each object, thus if you select 3 boxes, which rotate on center, then change the rotation, they all spin at the same time, and are set to the same rotation. If we are to do this, we likely will need a non-rectangular selection, which will take more time, and then the effect on the other halo menus is in question - sriggins

Future Revisions

Put the discreet rotation buttons into the hud. Change the halo menu button to show the halo hud if single clicked. -sriggins

Huds not part of the page work area

Now because the properties hud moves around the frame, it is possible to have the hud completely off screen and usable. We should consider making huds affect the page work area size -- sriggins