Bug 606343, part 1, add centering position types for panels, r=neil, a=blocking

This commit is contained in:
Neil Deakin 2010-12-05 17:09:36 -05:00
Родитель 5214b9dcf8
Коммит f86b23f261
4 изменённых файлов: 110 добавлений и 16 удалений

Просмотреть файл

@ -541,6 +541,14 @@ nsMenuPopupFrame::InitPositionFromAnchorAlign(const nsAString& aAnchor,
mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
else if (aAnchor.EqualsLiteral("bottomright"))
mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
else if (aAnchor.EqualsLiteral("leftcenter"))
mPopupAnchor = POPUPALIGNMENT_LEFTCENTER;
else if (aAnchor.EqualsLiteral("rightcenter"))
mPopupAnchor = POPUPALIGNMENT_RIGHTCENTER;
else if (aAnchor.EqualsLiteral("topcenter"))
mPopupAnchor = POPUPALIGNMENT_TOPCENTER;
else if (aAnchor.EqualsLiteral("bottomcenter"))
mPopupAnchor = POPUPALIGNMENT_BOTTOMCENTER;
else
mPopupAnchor = POPUPALIGNMENT_NONE;
@ -596,7 +604,14 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
mFlipBoth = flip.EqualsLiteral("both");
if (position.EqualsLiteral("before_start")) {
position.CompressWhitespace();
PRInt32 spaceIdx = position.FindChar(' ');
// if there is a space in the position, assume it is the anchor and
// alignment as two separate tokens.
if (spaceIdx >= 0) {
InitPositionFromAnchorAlign(Substring(position, 0, spaceIdx), Substring(position, spaceIdx + 1));
}
else if (position.EqualsLiteral("before_start")) {
mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
}
@ -879,20 +894,43 @@ nsMenuPopupFrame::GetRootViewForPopup(nsIFrame* aStartFrame)
}
nsPoint
nsMenuPopupFrame::AdjustPositionForAnchorAlign(const nsRect& anchorRect,
nsMenuPopupFrame::AdjustPositionForAnchorAlign(nsRect& anchorRect,
FlipStyle& aHFlip, FlipStyle& aVFlip)
{
// flip the anchor and alignment for right-to-left
PRInt8 popupAnchor(mPopupAnchor);
PRInt8 popupAlign(mPopupAlignment);
if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
popupAnchor = -popupAnchor;
// no need to flip the centered anchor types
if (popupAnchor < POPUPALIGNMENT_LEFTCENTER) {
popupAnchor = -popupAnchor;
}
popupAlign = -popupAlign;
}
// first, determine at which corner of the anchor the popup should appear
nsPoint pnt;
switch (popupAnchor) {
case POPUPALIGNMENT_LEFTCENTER:
pnt = nsPoint(anchorRect.x, anchorRect.y + anchorRect.height / 2);
anchorRect.y = pnt.y;
anchorRect.height = 0;
break;
case POPUPALIGNMENT_RIGHTCENTER:
pnt = nsPoint(anchorRect.XMost(), anchorRect.y + anchorRect.height / 2);
anchorRect.y = pnt.y;
anchorRect.height = 0;
break;
case POPUPALIGNMENT_TOPCENTER:
pnt = nsPoint(anchorRect.x + anchorRect.width / 2, anchorRect.y);
anchorRect.x = pnt.x;
anchorRect.width = 0;
break;
case POPUPALIGNMENT_BOTTOMCENTER:
pnt = nsPoint(anchorRect.x + anchorRect.width / 2, anchorRect.YMost());
anchorRect.x = pnt.x;
anchorRect.width = 0;
break;
case POPUPALIGNMENT_TOPRIGHT:
pnt = anchorRect.TopRight();
break;
@ -944,13 +982,26 @@ nsMenuPopupFrame::AdjustPositionForAnchorAlign(const nsRect& anchorRect,
// however horizontally, we want to to use the inside edges so the popup
// still appears underneath the anchor menu instead of floating off the
// side of the menu.
FlipStyle anchorEdge = mFlipBoth ? FlipStyle_Inside: FlipStyle_None;
aHFlip = (popupAnchor == -popupAlign) ? FlipStyle_Outside : anchorEdge;
if (((popupAnchor > 0) == (popupAlign > 0)) ||
(popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT))
aVFlip = FlipStyle_Outside;
else
aVFlip = anchorEdge;
if (popupAnchor >= POPUPALIGNMENT_LEFTCENTER) {
if (popupAnchor == POPUPALIGNMENT_LEFTCENTER ||
popupAnchor == POPUPALIGNMENT_RIGHTCENTER) {
aHFlip = FlipStyle_Outside;
aVFlip = FlipStyle_Inside;
}
else {
aHFlip = FlipStyle_Inside;
aVFlip = FlipStyle_Outside;
}
}
else {
FlipStyle anchorEdge = mFlipBoth ? FlipStyle_Inside : FlipStyle_None;
aHFlip = (popupAnchor == -popupAlign) ? FlipStyle_Outside : anchorEdge;
if (((popupAnchor > 0) == (popupAlign > 0)) ||
(popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT))
aVFlip = FlipStyle_Outside;
else
aVFlip = anchorEdge;
}
return pnt;
}

Просмотреть файл

@ -109,6 +109,11 @@ enum FlipStyle {
#define POPUPALIGNMENT_BOTTOMLEFT 2
#define POPUPALIGNMENT_BOTTOMRIGHT -2
#define POPUPALIGNMENT_LEFTCENTER 16
#define POPUPALIGNMENT_RIGHTCENTER 17
#define POPUPALIGNMENT_TOPCENTER 18
#define POPUPALIGNMENT_BOTTOMCENTER 19
#define INC_TYP_INTERVAL 1000 // 1s. If the interval between two keypresses is shorter than this,
// treat as a continue typing
// XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
@ -354,7 +359,7 @@ protected:
// return the position where the popup should be, when it should be
// anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
// flipped in that direction if there is not enough space available.
nsPoint AdjustPositionForAnchorAlign(const nsRect& anchorRect,
nsPoint AdjustPositionForAnchorAlign(nsRect& anchorRect,
FlipStyle& aHFlip, FlipStyle& aVFlip);
// check if the popup will fit into the available space and resize it. This

Просмотреть файл

@ -326,6 +326,33 @@ function compareEdge(anchor, popup, edge, offsetX, offsetY, testname)
(Math.round(popuprect.bottom) - Math.round(popuprect.top)),
testname + " size");
var spaceIdx = edge.indexOf(" ");
if (spaceIdx > 0) {
let cornerX, cornerY;
let [anchor, align] = edge.split(" ");
switch (anchor) {
case "topleft": cornerX = anchorrect.left; cornerY = anchorrect.top; break;
case "topcenter": cornerX = anchorrect.left + anchorrect.width / 2; cornerY = anchorrect.top; break;
case "topright": cornerX = anchorrect.right; cornerY = anchorrect.top; break;
case "leftcenter": cornerX = anchorrect.left; cornerY = anchorrect.top + anchorrect.height / 2; break;
case "rightcenter": cornerX = anchorrect.right; cornerY = anchorrect.top + anchorrect.height / 2; break;
case "bottomleft": cornerX = anchorrect.left; cornerY = anchorrect.bottom; break;
case "bottomcenter": cornerX = anchorrect.left + anchorrect.width / 2; cornerY = anchorrect.bottom; break;
case "bottomright": cornerX = anchorrect.right; cornerY = anchorrect.bottom; break;
}
switch (align) {
case "topleft": cornerX += offsetX; cornerY += offsetY; break;
case "topright": cornerX += -popuprect.width + offsetX; cornerY += offsetY; break;
case "bottomleft": cornerX += offsetX; cornerY += -popuprect.height + offsetY; break;
case "bottomright": cornerX += -popuprect.width + offsetX; cornerY += -popuprect.height + offsetY; break;
}
is(Math.round(popuprect.left), Math.round(cornerX), testname + " x position");
is(Math.round(popuprect.top), Math.round(cornerY), testname + " y position");
return;
}
if (edge == "after_pointer") {
is(Math.round(popuprect.left), Math.round(anchorrect.left) + offsetX, testname + " x position");
is(Math.round(popuprect.top), Math.round(anchorrect.top) + offsetY + 21, testname + " y position");

Просмотреть файл

@ -170,7 +170,11 @@ var popupTests = [
events: [ "popupshowing thepopup", "popupshown thepopup" ],
autohide: "thepopup",
steps: ["before_start", "before_end", "after_start", "after_end",
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
"topleft topleft", "topcenter topleft", "topright topleft",
"leftcenter topright", "rightcenter topright",
"bottomleft bottomleft", "bottomcenter bottomleft", "bottomright bottomleft",
"topleft bottomright", "bottomcenter bottomright", "rightcenter topright"],
test: function(testname, step) {
gExpectedTriggerNode = "notset";
gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
@ -190,16 +194,22 @@ var popupTests = [
events: [ "popupshowing thepopup", "popupshown thepopup" ],
autohide: "thepopup",
steps: ["before_start", "before_end", "after_start", "after_end",
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
"topleft topleft", "topcenter topleft", "topright topleft",
"leftcenter topright", "rightcenter topright",
"bottomleft bottomleft", "bottomcenter bottomleft", "bottomright bottomleft",
"topleft bottomright", "bottomcenter bottomright", "rightcenter topright"],
test: function(testname, step) {
gMenuPopup.setAttribute("style", "margin: 10px;");
gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false);
},
result: function(testname, step) {
var rightmod = step == "before_end" || step == "after_end" ||
step == "start_before" || step == "start_after";
step == "start_before" || step == "start_after" ||
step.match(/topright$/) || step.match(/bottomright$/);
var bottommod = step == "before_start" || step == "before_end" ||
step == "start_after" || step == "end_after";
step == "start_after" || step == "end_after" ||
step.match(/bottomleft$/) || step.match(/bottomright$/);
compareEdge(gTrigger, gMenuPopup, step, rightmod ? -10 : 10, bottommod ? -10 : 10, testname);
gMenuPopup.removeAttribute("style");
}
@ -231,7 +241,8 @@ var popupTests = [
events: [ "popupshowing thepopup", "popupshown thepopup" ],
autohide: "thepopup",
steps: ["before_start", "before_end", "after_start", "after_end",
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap"],
"start_before", "start_after", "end_before", "end_after", "after_pointer", "overlap",
"topcenter topleft", "topright bottomright", "leftcenter topright"],
test: function(testname, step) {
gMenuPopup.setAttribute("position", step);
gMenuPopup.openPopup(gTrigger, "", 0, 0, false, false);