use of edu.cmu.cs.hcii.cogtool.model.DoubleRectangle in project cogtool by cogtool.
the class FrameEditorController method reorderWidget.
private boolean reorderWidget(final IWidget widget, final SimpleWidgetGroup newGroup, final int newIndex) {
final SimpleWidgetGroup prevGroup = widget.getParentGroup();
final int prevIndex = prevGroup.indexOf(widget);
int index = newIndex;
if (prevGroup == newGroup) {
if (prevIndex < newIndex) {
index--;
}
if (index == prevIndex) {
return true;
}
}
DoublePoint prevGroupStartPos = prevGroup.get(0).getShape().getOrigin();
final double prevGroupStartX = prevGroupStartPos.x;
final double prevGroupStartY = prevGroupStartPos.y;
DoubleSize prevSize = widget.getShape().getSize();
final double prevWidth = prevSize.width;
final double prevHeight = prevSize.height;
DoubleRectangle newBds = newGroup.get(0).getEltBounds();
double heightFactor = (widget instanceof ListItem) ? getHeightFactor(widget, newGroup) : 1.0;
final double newWidth = newBds.width;
final double newHeight = newBds.height * heightFactor;
final double newGroupStartX = newBds.x;
final double newGroupStartY = newBds.y;
Object rendered = newGroup.getAttribute(WidgetAttributes.IS_RENDERED_ATTR);
final boolean groupRendered = ((Boolean) rendered).booleanValue();
final boolean widgetRendered = widget.isRendered();
reorderGroupWidget(widget, newWidth, newHeight, index, prevGroup, newGroup, prevGroupStartX, prevGroupStartY, newGroupStartX, newGroupStartY);
if (widgetRendered != groupRendered) {
widget.setRendered(groupRendered);
}
DemoStateManager.ObsoletingEdit edit = new DemoStateManager.ObsoletingEdit(FrameEditorLID.Reorder, demoStateMgr) {
@Override
public String getPresentationName() {
return REORDER_WIDGET;
}
@Override
public void redo() {
super.redo();
int index = newIndex;
if (prevGroup == newGroup) {
if (prevIndex < newIndex) {
index--;
}
}
reorderGroupWidget(widget, newWidth, newHeight, index, prevGroup, newGroup, prevGroupStartX, prevGroupStartY, newGroupStartX, newGroupStartY);
if (widgetRendered != groupRendered) {
widget.setRendered(groupRendered);
}
noteEditCheckRegenerate(prevGroup, newGroup, this);
}
@Override
public void undo() {
super.undo();
reorderGroupWidget(widget, prevWidth, prevHeight, prevIndex, newGroup, prevGroup, newGroupStartX, newGroupStartY, prevGroupStartX, prevGroupStartY);
if (widgetRendered != groupRendered) {
widget.setRendered(widgetRendered);
}
noteEditCheckRegenerate(newGroup, prevGroup, this);
}
};
noteEditCheckRegenerate(prevGroup, newGroup, edit);
undoMgr.addEdit(edit);
return true;
}
use of edu.cmu.cs.hcii.cogtool.model.DoubleRectangle in project cogtool by cogtool.
the class FrameEditorController method spaceElementsEqually.
/**
* Spaces the selected frame elements equally along a certain axis
* @param vertical true for vertical axis; false for horizontal
*/
private boolean spaceElementsEqually(FrameEditorSelectionState selection, boolean vertical) {
// Order the widgets according to location
// (either from the left or from the top)
Comparator<FrameElement> c = vertical ? elementVerticalComparator : elementHorizontalComparator;
Set<FrameElement> elements = getSelectedElements(selection, c);
if (elements.size() <= 2) {
interaction.protestTooFewElements();
return false;
}
// Calculate the spacing between widgets
double sum = 0;
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
// Go through each element that is selected
// Determine the size, min & max of the region.
// this can then be used to do spacing.
Iterator<FrameElement> eltIter = elements.iterator();
while (eltIter.hasNext()) {
DoubleRectangle bounds = eltIter.next().getEltBounds();
double size = vertical ? bounds.height : bounds.width;
double position = vertical ? bounds.y : bounds.x;
sum += size;
min = Math.min(min, position);
max = Math.max(max, size + position);
}
// Get the spacing to use between each item.
double spacing = ((max - min) - sum) / (elements.size() - 1);
String undoRedoLabel = vertical ? SPACE_VERTICALLY : SPACE_HORIZONTALLY;
CogToolLID lid = vertical ? FrameEditorLID.SpaceVertically : FrameEditorLID.SpaceHorizontally;
CompoundUndoableEdit editSequence = new CompoundUndoableEdit(undoRedoLabel, lid);
// Avoid moving a group more than once
Set<SimpleWidgetGroup> movedGroups = new HashSet<SimpleWidgetGroup>();
Set<IWidget> movedWidgets = new HashSet<IWidget>();
// Adjust the spacings to the correct values and go through
// each element performing the appropriate move.
eltIter = elements.iterator();
while (eltIter.hasNext()) {
FrameElement elt = eltIter.next();
DoubleRectangle bounds = elt.getEltBounds();
// Determine the amount to move each element
double deltaX = vertical ? 0.0 : (min - bounds.x);
double deltaY = vertical ? (min - bounds.y) : 0.0;
// Set the new location, adding the undoable edit
moveElement(lid, undoRedoLabel, elt, deltaX, deltaY, true, movedGroups, movedWidgets, editSequence);
// Advance the pointer to the next location
min += spacing + (vertical ? bounds.height : bounds.width);
}
editSequence.end();
// Only add this edit if it is significant
if (editSequence.isSignificant()) {
undoMgr.addEdit(editSequence);
}
return true;
}
use of edu.cmu.cs.hcii.cogtool.model.DoubleRectangle in project cogtool by cogtool.
the class FrameEditorController method captureImageAction.
// createChangeAuxTextPropertyAction
/**
* Create a ListenerAction which will handle capturing a background image.
* @return
*/
private IListenerAction captureImageAction() {
return new IListenerAction() {
public Class<?> getParameterClass() {
return FrameEditorSelectionState.class;
}
public boolean performAction(Object prms) {
CompoundUndoableEdit editSequence = new CompoundUndoableEdit(CAPTURE_BKG_IMG, FrameEditorLID.CaptureImageProperty);
// Get the selection.
FrameEditorSelectionState selection = (FrameEditorSelectionState) prms;
Iterator<IWidget> selected = selection.getSelectedWidgetsIterator();
// Iterate over every selected widget
while (selected.hasNext()) {
final IWidget w = selected.next();
DoubleRectangle bounds = w.getEltBounds();
// Get the image from the background, and crop to shape
final byte[] bg = GraphicsUtil.cropImage(model.getBackgroundImage(), bounds.x, bounds.y, bounds.width, bounds.height);
// Get the old image, could be null.
final byte[] old = w.getImage();
final String previousImagePath = (String) w.getAttribute(WidgetAttributes.IMAGE_PATH_ATTR);
w.setImage(bg);
w.setAttribute(WidgetAttributes.IMAGE_PATH_ATTR, WidgetAttributes.NO_IMAGE);
editSequence.addEdit(new AUndoableEdit(FrameEditorLID.CaptureImageProperty) {
@Override
public String getPresentationName() {
return CAPTURE_BKG_IMG;
}
@Override
public void redo() {
super.redo();
w.setImage(bg);
w.setAttribute(WidgetAttributes.IMAGE_PATH_ATTR, WidgetAttributes.NO_IMAGE);
}
@Override
public void undo() {
super.undo();
w.setImage(old);
w.setAttribute(WidgetAttributes.IMAGE_PATH_ATTR, previousImagePath);
}
});
}
editSequence.end();
// Only add this edit if it is significant
if (editSequence.isSignificant()) {
undoMgr.addEdit(editSequence);
}
return true;
}
};
}
use of edu.cmu.cs.hcii.cogtool.model.DoubleRectangle in project cogtool by cogtool.
the class BalsamiqButtonAPIConverter method parseBMMLWidget.
/** Helper function used by parseFrame
* This method is used to parse the tags of each control tag in Balsamiq XML. A control tag
* represents a Balsamiq Widget.
*
* @param node a node of the tree that represents a Balsamiq widget
* @frame frame that the widget is being added to
* @group parent group
* @groupX x coordinate of parent group
* @groupY y coordinate of parent group
* @return the newly created widget
*/
protected Widget parseBMMLWidget(Node node, Frame frame, SimpleWidgetGroup group, double groupX, double groupY) throws IOException {
System.out.println("parseBMMLWidget " + group + " x: " + groupX + "y: " + groupY);
NodeList children = node.getChildNodes();
Widget widget = null;
WidgetType widgetType = null;
String balsamiqControlType = getAttributeValue(node, CONTROL_TYPE_ATTR);
String widgetTypeString = (balsamiqControlType == null) ? null : getBMMLWidgetType(balsamiqControlType);
String widgetName = getAttributeValue(node, CONTROL_ID_ATTR);
if (widgetName == null) {
//TODO: make a random widget name and move on. report to the user. need to be unique within the frame. Frame.java has a method for this
}
System.out.println("462- wN " + widgetName + "widT " + widgetTypeString);
if (widgetTypeString == null) {
//TODO: report to the user
} else {
widgetType = getWidgetType(widgetTypeString);
//Parse the widget name, location and size from the attributes of the XML tag
//TODO: Error check all of the getAttributeValues()
double x = Double.parseDouble(getAttributeValue(node, X_ATTR));
double y = Double.parseDouble(getAttributeValue(node, Y_ATTR));
//TODO: difference between w and measuredW, same for height
double width = Integer.parseInt(getAttributeValue(node, BWIDTH_ATTR));
double height = Integer.parseInt(getAttributeValue(node, BHEIGHT_ATTR));
double measWidth = Integer.parseInt(getAttributeValue(node, MEASURED_WIDTH_ATTR));
double measHeight = Integer.parseInt(getAttributeValue(node, MEASURED_HEIGHT_ATTR));
if (//TODO: make sure the dimensions are positive
width == -1 && height == -1) {
System.out.println("493- changing widget dimensions");
width = measWidth;
height = measHeight;
}
/*bounds is the size and location of the widget*/
if (group != null) {
System.out.println("488-Group is not null");
DoubleRectangle rect = group.getGroupBounds();
if (rect != null) {
System.out.println("500-rect is not null");
//x += groupX;
//y += groupY;
}
}
x += groupX;
y += groupY;
System.out.println("new widget has dimens:" + x + " " + y);
DoubleRectangle bounds = new DoubleRectangle(x, y, width, height);
if (widgetType == WidgetType.Check) {
System.out.println("505-The widget is a check so now make a group for it");
if (group == null) {
group = new GridButtonGroup();
//give it a random widget name
group.setName("newName");
groupRegistry.put("newName", group);
}
//if(group instanceof GridButtonGroup)
//{
int eltCount = group.elementCount();
System.out.println("513-group is gridbuttongroup " + group.getName() + " " + eltCount);
if (eltCount > 0) {
//TODO: check if the widgets align best horizontally or vertically
//align the widgets to average coord, first, left or rightmost
IWidget wid = group.getElement(group.elementCount() - 1);
DoubleRectangle bounds2 = wid.getEltBounds();
System.out.println("530 " + bounds2.getX() + " " + bounds2.getWidth() + " " + bounds2.getY() + " " + bounds2.getHeight());
double diffX = Math.abs(x - bounds2.getX());
double diffY = Math.abs(y - bounds2.getY());
System.out.println("diffX " + diffX + " " + diffY);
DoubleRectangle bounds3 = new DoubleRectangle(bounds2.getX() + bounds2.getWidth(), bounds2.getY(), width, height);
if (diffX < diffY) {
bounds3 = new DoubleRectangle(bounds2.getX(), bounds2.getY() + bounds2.getHeight(), width, height);
}
widget = new CheckBox((GridButtonGroup) group, bounds3, widgetName);
} else {
widget = new CheckBox((GridButtonGroup) group, bounds, widgetName);
}
widget.setWidgetType(widgetType);
/*}
else
{
System.out.println("517-group2 is gridbuttongroup");
GridButtonGroup group2 = new GridButtonGroup();
group2.setName("newNameCheck");
groupRegistry.put("newNameCheck", group2);
widget = new CheckBox(group2, bounds, widgetName);
//group.addElement((IWidget) group2);
}*/
} else {
widget = new Widget(bounds, widgetType);
}
widget.setName(widgetName);
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
String nodeName = child.getNodeName();
/*Whitespace in the DOM tree is represented as #text. Ignore these nodes. Anywhere between the open and closed tag*/
if (!nodeName.equals("#text")) {
if (nodeName.equalsIgnoreCase(CONTROL_PROP_ELT)) {
NodeList controlTags = child.getChildNodes();
for (int j = 0; j < controlTags.getLength(); j++) {
Node controlTag = controlTags.item(j);
String propertyTag = controlTag.getNodeName();
//CogTool widget Display Label
if (propertyTag.equalsIgnoreCase(BALSAMIQ_TEXT_ELT)) {
/*Must decode the title. For instance the title in
Balsamiq, "First%20Frame" is "First Frame" in CogTool*/
String title = getElementText(controlTag);
title = URLDecoder.decode(title, "UTF-8");
widget.setTitle(title);
} else //CogTool transition on the present widget
if (propertyTag.equalsIgnoreCase(HREF_ELT)) {
String destinationFileName = getElementText(controlTag);
File destinationFile = new File(designPathName, destinationFileName);
//Make sure the file exists before attempting to parse the file
if (destinationFile.exists()) {
parseBalsamiqFile(destinationFile);
parseTransition(destinationFileName, widget);
}
} else if (propertyTag.equalsIgnoreCase(STATE_ELT)) {
//TODO: work on states
//A Balsamiq Button can be normal, selected, or disabled
String state = getElementText(controlTag);
if (state.equals("selected")) {
widget.setAttribute(WidgetAttributes.IS_SELECTED_ATTR, Boolean.TRUE);
} else {
//TODO: Other Balsamiq states like "disabled", "disabled and selected"
}
}
// END OF STATE OF BUTTON
}
// END OF PROPERTY TAG
}
// END OF CONTROL PROPERTIES TAG
}
}
}
widget.setRendered(true);
return widget;
}
use of edu.cmu.cs.hcii.cogtool.model.DoubleRectangle in project cogtool by cogtool.
the class DesignExportToHTML method buildWidgetHTML.
protected String buildWidgetHTML(IWidget widget, Set<SimpleWidgetGroup> visitedGroups, Frame frame) {
//Function is called once for each widget...
StringBuilder html = new StringBuilder();
DoubleRectangle bounds = widget.getEltBounds();
String name = widget.getName();
//How does below boolean work?
boolean isStandard = widget.isStandard();
//MAYBE CREATE AN IF STATEMENT TO HANDLE BUTTONS/MENU BUTTON DIFFERENTLY
// Put the html widget in the same place as the CogTool widget
// (adjusting for the position of the html table)
//WE ARE ADDING TEN HERE TO COMPENSATE FOR LOCATION WITHIN BROWSER
//WE DO NOT WANT TO ADD THAT SINCE WE ARE SWITCHING TO AREA TAG AND DEALING WITHIN IMAGE ONLY
//POSITION AS OF NOW IS RELATIVE TO IMAGE :)
String properties = "onfocus=\"onFocus('" + name + "')\" onblur=\"onBlur()\"" + " id=\"" + name + "\" style=\"position: absolute; left: " + (bounds.x + 10) + "; top: " + (bounds.y + 33) + "; width: " + bounds.width + "; height: " + bounds.height + ";\"";
WidgetType type = widget.getWidgetType();
// don't pop up the "does not help..." message if there is no left click
// transition defined from these widgets
int ignoreButton = 0;
boolean ignoreLeftClick = (WidgetType.Check.equals(type) || WidgetType.TextBox.equals(type) || WidgetType.Graffiti.equals(type) || WidgetType.Menu.equals(type));
if (ignoreLeftClick) {
ignoreButton = LEFT_MOUSE;
} else if (WidgetType.ContextMenu.equals(type)) {
ignoreButton = RIGHT_MOUSE;
}
String eventString = getEventString(widget, ignoreButton);
if (!widget.isRendered() && "".equals(widget.getTitle()) && widget.getImage() == null && frame.getBackgroundImage() == null && !WidgetType.Noninteractive.equals(type)) {
blindHotSpotWarning += "This CogTool model has a hidden widget on screen. " + "You will not be able to visibly identify the location of +" + widget.getName() + ".\n";
}
//Why did they not use a switch statement here ?
if (isStandard) {
if (WidgetType.Noninteractive.equals(type) || WidgetType.Text.equals(type)) {
return getHotspotString(widget, properties, eventString);
}
if (WidgetType.Button.equals(type)) {
if (!widget.isRendered()) {
if (!"".equals(widget.getTitle())) {
html.append("<div align=\"middle\"" + properties + eventString + ">" + widget.getTitle() + "</div>\n");
}
//In the below 6 lines I create an area tag that will be placed within the map tags, within the html code,
//in order to create HotSpots over the image of the frame
mapHTML += "<area shape=\"rect\" name=value ";
mapHTML += "value ='" + widget.getTitle() + "'";
mapHTML += " onfocus=\"onFocus('" + name + "')\" onblur=\"onBlur()\"" + " id=\"" + name + "\"" + " coords=\"" + bounds.x + "," + bounds.y + "," + (bounds.x + bounds.width) + "," + (bounds.y + bounds.height) + "\"";
mapHTML += eventString + "/>\n";
} else {
html.append("<input type=button name=value value='");
html.append(widget.getTitle());
html.append("' " + properties + eventString + ">\n");
}
} else if (WidgetType.Check.equals(type)) {
String checked = "";
Object isSel = widget.getAttribute(WidgetAttributes.IS_SELECTED_ATTR);
if (NullSafe.equals(WidgetAttributes.IS_SELECTED, isSel)) {
checked = " checked";
}
// for checkboxes, width and height don't matter, so only deal with
// the x and y
String styleString = properties.substring(0, properties.indexOf("width")) + "\"";
html.append("<input type=checkbox " + styleString + eventString);
html.append(checked + ">\n");
String textStyle = "style=\"position: absolute; left: " + (bounds.x + 30) + "; top: " + (bounds.y + 33) + ";\"";
String textEvent = eventString;
if (textSelect(widget)) {
textEvent += " onclick=\"toggleCheckbox('";
textEvent += widget.getName();
textEvent += "')\"";
}
html.append("<a " + textStyle + textEvent + ">");
html.append(widget.getTitle() + "</a>\n");
} else if (WidgetType.Radio.equals(type)) {
SimpleWidgetGroup group = widget.getParentGroup();
if ((group != null) && !visitedGroups.contains(group)) {
visitedGroups.add(group);
String groupName = widget.getName();
Iterator<IWidget> widgets = group.iterator();
while (widgets.hasNext()) {
IWidget w = widgets.next();
DoublePoint origin = w.getShape().getOrigin();
String itemString = getEventString(w, LEFT_MOUSE);
String checked = "";
Object isSel = w.getAttribute(WidgetAttributes.IS_SELECTED_ATTR);
if (NullSafe.equals(WidgetAttributes.IS_SELECTED, isSel)) {
checked = " checked";
}
// for radio buttons, width and height don't matter, so only deal with
// the x and y
String styleString = "onfocus=\"onFocus('" + w.getName() + "')\" onblur=\"onBlur()\"" + "style=\"position: absolute; left: " + (origin.x + 10) + "; top: " + (origin.y + 33) + ";\"";
// TODO: if transitioned from, never deselects
html.append("<input type=radio name=\"" + groupName + "\"");
html.append(" id=\"");
html.append(w.getName());
html.append("\" " + styleString + itemString + checked + ">\n");
String textStyle = "style=\"position: absolute; left: " + (origin.x + 30) + "; top: " + (origin.y + 33) + ";\"";
String textEvent = itemString;
if (textSelect(w)) {
textEvent += " onclick=\"selectRadio('";
textEvent += w.getName();
textEvent += "')\"";
}
html.append("<a " + textStyle + textEvent + ">");
html.append(w.getTitle() + "</a>\n");
}
}
} else if (WidgetType.TextBox.equals(type) || WidgetType.Graffiti.equals(type)) {
html.append("<input type=text name=value value='");
html.append(widget.getTitle());
html.append("' " + properties + eventString + ">\n");
} else if (widget instanceof ListItem) {
SimpleWidgetGroup group = widget.getParentGroup();
// this code will change
if (!(visitedGroups.contains(group))) {
visitedGroups.add(group);
ListItem firstItem = (ListItem) group.get(0);
DoubleRectangle itemBounds = firstItem.getEltBounds();
// use properties of the first item in the list
properties = "onfocus=\"onFocus('" + firstItem.getName() + "')\" onblur=\"onBlur()\"" + " id=\"" + firstItem.getName() + "\" style=\"position: absolute; left: " + (itemBounds.x + 10) + "; top: " + (itemBounds.y + 33) + "; width: " + itemBounds.width + ";\"";
html.append("<select size=" + group.size() + " " + properties + ">\n");
Iterator<IWidget> widgets = group.iterator();
while (widgets.hasNext()) {
IWidget w = widgets.next();
String itemEvent = getEventString(w, 0);
html.append("<option" + itemEvent + " id=\"");
html.append(w.getName() + "\">");
html.append(w.getTitle() + "\n");
}
html.append("</select>\n");
}
} else if (widget instanceof MenuHeader) {
// make hotspot associated w/ menu, use widget's
// name for ID
// html.append("<input type=button name=value value='");
// html.append(widget.getTitle());
// html.append("' style=" + style + " id=\"");
// html.append(widget.getName());
// html.append("\">\n");
// TODO: add background color?
properties = properties.substring(0, properties.length() - 1);
properties += " background: lightGray;\"";
html.append("<div " + properties + eventString + ">");
html.append(widget.getTitle());
html.append("</div>\n");
} else if (widget instanceof ContextMenu) {
// TODO: add background color?
// style = style.substring(0, style.length() - 1);
// style += " background: lightGray;\"";
html.append("<div " + properties + eventString + ">");
html.append(widget.getTitle());
html.append("</div>\n");
} else if (widget instanceof PullDownHeader) {
PullDownHeader pdh = (PullDownHeader) widget;
//"select tag is used to create a select list" --> http://www.w3schools.com/TAGS/tag_Select.asp
html.append("<select " + properties + ">\n");
if (pdh.itemCount() > 0) {
//html.append("<optgroup>\n"); //TODO: style
Iterator<IWidget> children = pdh.getChildren().iterator();
while (children.hasNext()) {
IWidget pdi = children.next();
String childEvent = getEventString(pdi, 0);
html.append("<option" + childEvent + " id=\"");
html.append(pdi.getName() + "\">" + pdi.getTitle() + "\n");
}
//html.append("</optgroup>\n");
}
html.append("</select>\n");
} else if (WidgetType.Link.equals(type)) {
properties = properties.substring(0, properties.length() - 1);
html.append("<a " + properties + " color: blue;\"");
html.append(eventString + "><u>");
html.append(widget.getTitle());
html.append("</u></a>\n");
}
} else {
// unknown widget or custom version of an interactive widget
return getHotspotString(widget, properties, eventString);
}
return html.toString();
}
Aggregations