layout/xul/nsSplitterFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 //
michael@0 7 // Eric Vaughan
michael@0 8 // Netscape Communications
michael@0 9 //
michael@0 10 // See documentation in associated header file
michael@0 11 //
michael@0 12
michael@0 13 #include "nsSplitterFrame.h"
michael@0 14 #include "nsGkAtoms.h"
michael@0 15 #include "nsIDOMElement.h"
michael@0 16 #include "nsIDOMXULElement.h"
michael@0 17 #include "nsPresContext.h"
michael@0 18 #include "nsRenderingContext.h"
michael@0 19 #include "nsIDocument.h"
michael@0 20 #include "nsNameSpaceManager.h"
michael@0 21 #include "nsScrollbarButtonFrame.h"
michael@0 22 #include "nsIDOMEventListener.h"
michael@0 23 #include "nsIDOMMouseEvent.h"
michael@0 24 #include "nsIPresShell.h"
michael@0 25 #include "nsFrameList.h"
michael@0 26 #include "nsHTMLParts.h"
michael@0 27 #include "nsStyleContext.h"
michael@0 28 #include "nsBoxLayoutState.h"
michael@0 29 #include "nsIServiceManager.h"
michael@0 30 #include "nsContainerFrame.h"
michael@0 31 #include "nsAutoPtr.h"
michael@0 32 #include "nsContentCID.h"
michael@0 33 #include "nsStyleSet.h"
michael@0 34 #include "nsLayoutUtils.h"
michael@0 35 #include "nsDisplayList.h"
michael@0 36 #include "nsContentUtils.h"
michael@0 37 #include "mozilla/dom/Element.h"
michael@0 38 #include "mozilla/MouseEvents.h"
michael@0 39
michael@0 40 using namespace mozilla;
michael@0 41
michael@0 42 class nsSplitterInfo {
michael@0 43 public:
michael@0 44 nscoord min;
michael@0 45 nscoord max;
michael@0 46 nscoord current;
michael@0 47 nscoord changed;
michael@0 48 nsCOMPtr<nsIContent> childElem;
michael@0 49 int32_t flex;
michael@0 50 int32_t index;
michael@0 51 };
michael@0 52
michael@0 53 class nsSplitterFrameInner : public nsIDOMEventListener
michael@0 54 {
michael@0 55 public:
michael@0 56
michael@0 57 NS_DECL_ISUPPORTS
michael@0 58 NS_DECL_NSIDOMEVENTLISTENER
michael@0 59
michael@0 60 nsSplitterFrameInner(nsSplitterFrame* aSplitter)
michael@0 61 {
michael@0 62 mOuter = aSplitter;
michael@0 63 mPressed = false;
michael@0 64 }
michael@0 65 virtual ~nsSplitterFrameInner();
michael@0 66
michael@0 67 void Disconnect() { mOuter = nullptr; }
michael@0 68
michael@0 69 nsresult MouseDown(nsIDOMEvent* aMouseEvent);
michael@0 70 nsresult MouseUp(nsIDOMEvent* aMouseEvent);
michael@0 71 nsresult MouseMove(nsIDOMEvent* aMouseEvent);
michael@0 72
michael@0 73 void MouseDrag(nsPresContext* aPresContext, WidgetGUIEvent* aEvent);
michael@0 74 void MouseUp(nsPresContext* aPresContext, WidgetGUIEvent* aEvent);
michael@0 75
michael@0 76 void AdjustChildren(nsPresContext* aPresContext);
michael@0 77 void AdjustChildren(nsPresContext* aPresContext, nsSplitterInfo* aChildInfos, int32_t aCount, bool aIsHorizontal);
michael@0 78
michael@0 79 void AddRemoveSpace(nscoord aDiff,
michael@0 80 nsSplitterInfo* aChildInfos,
michael@0 81 int32_t aCount,
michael@0 82 int32_t& aSpaceLeft);
michael@0 83
michael@0 84 void ResizeChildTo(nsPresContext* aPresContext,
michael@0 85 nscoord& aDiff,
michael@0 86 nsSplitterInfo* aChildrenBeforeInfos,
michael@0 87 nsSplitterInfo* aChildrenAfterInfos,
michael@0 88 int32_t aChildrenBeforeCount,
michael@0 89 int32_t aChildrenAfterCount,
michael@0 90 bool aBounded);
michael@0 91
michael@0 92 void UpdateState();
michael@0 93
michael@0 94 void AddListener(nsPresContext* aPresContext);
michael@0 95 void RemoveListener();
michael@0 96
michael@0 97 enum ResizeType { Closest, Farthest, Flex, Grow };
michael@0 98 enum State { Open, CollapsedBefore, CollapsedAfter, Dragging };
michael@0 99 enum CollapseDirection { Before, After };
michael@0 100
michael@0 101 ResizeType GetResizeBefore();
michael@0 102 ResizeType GetResizeAfter();
michael@0 103 State GetState();
michael@0 104
michael@0 105 void Reverse(nsSplitterInfo*& aIndexes, int32_t aCount);
michael@0 106 bool SupportsCollapseDirection(CollapseDirection aDirection);
michael@0 107
michael@0 108 void EnsureOrient();
michael@0 109 void SetPreferredSize(nsBoxLayoutState& aState, nsIFrame* aChildBox, nscoord aOnePixel, bool aIsHorizontal, nscoord* aSize);
michael@0 110
michael@0 111 nsSplitterFrame* mOuter;
michael@0 112 bool mDidDrag;
michael@0 113 nscoord mDragStart;
michael@0 114 nscoord mCurrentPos;
michael@0 115 nsIFrame* mParentBox;
michael@0 116 bool mPressed;
michael@0 117 nsSplitterInfo* mChildInfosBefore;
michael@0 118 nsSplitterInfo* mChildInfosAfter;
michael@0 119 int32_t mChildInfosBeforeCount;
michael@0 120 int32_t mChildInfosAfterCount;
michael@0 121 State mState;
michael@0 122 nscoord mSplitterPos;
michael@0 123 bool mDragging;
michael@0 124
michael@0 125 };
michael@0 126
michael@0 127 NS_IMPL_ISUPPORTS(nsSplitterFrameInner, nsIDOMEventListener)
michael@0 128
michael@0 129 nsSplitterFrameInner::ResizeType
michael@0 130 nsSplitterFrameInner::GetResizeBefore()
michael@0 131 {
michael@0 132 static nsIContent::AttrValuesArray strings[] =
michael@0 133 {&nsGkAtoms::farthest, &nsGkAtoms::flex, nullptr};
michael@0 134 switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None,
michael@0 135 nsGkAtoms::resizebefore,
michael@0 136 strings, eCaseMatters)) {
michael@0 137 case 0: return Farthest;
michael@0 138 case 1: return Flex;
michael@0 139 }
michael@0 140 return Closest;
michael@0 141 }
michael@0 142
michael@0 143 nsSplitterFrameInner::~nsSplitterFrameInner()
michael@0 144 {
michael@0 145 delete[] mChildInfosBefore;
michael@0 146 delete[] mChildInfosAfter;
michael@0 147 }
michael@0 148
michael@0 149 nsSplitterFrameInner::ResizeType
michael@0 150 nsSplitterFrameInner::GetResizeAfter()
michael@0 151 {
michael@0 152 static nsIContent::AttrValuesArray strings[] =
michael@0 153 {&nsGkAtoms::farthest, &nsGkAtoms::flex, &nsGkAtoms::grow, nullptr};
michael@0 154 switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None,
michael@0 155 nsGkAtoms::resizeafter,
michael@0 156 strings, eCaseMatters)) {
michael@0 157 case 0: return Farthest;
michael@0 158 case 1: return Flex;
michael@0 159 case 2: return Grow;
michael@0 160 }
michael@0 161 return Closest;
michael@0 162 }
michael@0 163
michael@0 164 nsSplitterFrameInner::State
michael@0 165 nsSplitterFrameInner::GetState()
michael@0 166 {
michael@0 167 static nsIContent::AttrValuesArray strings[] =
michael@0 168 {&nsGkAtoms::dragging, &nsGkAtoms::collapsed, nullptr};
michael@0 169 static nsIContent::AttrValuesArray strings_substate[] =
michael@0 170 {&nsGkAtoms::before, &nsGkAtoms::after, nullptr};
michael@0 171 switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None,
michael@0 172 nsGkAtoms::state,
michael@0 173 strings, eCaseMatters)) {
michael@0 174 case 0: return Dragging;
michael@0 175 case 1:
michael@0 176 switch (mOuter->GetContent()->FindAttrValueIn(kNameSpaceID_None,
michael@0 177 nsGkAtoms::substate,
michael@0 178 strings_substate,
michael@0 179 eCaseMatters)) {
michael@0 180 case 0: return CollapsedBefore;
michael@0 181 case 1: return CollapsedAfter;
michael@0 182 default:
michael@0 183 if (SupportsCollapseDirection(After))
michael@0 184 return CollapsedAfter;
michael@0 185 return CollapsedBefore;
michael@0 186 }
michael@0 187 }
michael@0 188 return Open;
michael@0 189 }
michael@0 190
michael@0 191 //
michael@0 192 // NS_NewSplitterFrame
michael@0 193 //
michael@0 194 // Creates a new Toolbar frame and returns it
michael@0 195 //
michael@0 196 nsIFrame*
michael@0 197 NS_NewSplitterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 198 {
michael@0 199 return new (aPresShell) nsSplitterFrame(aPresShell, aContext);
michael@0 200 }
michael@0 201
michael@0 202 NS_IMPL_FRAMEARENA_HELPERS(nsSplitterFrame)
michael@0 203
michael@0 204 nsSplitterFrame::nsSplitterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 205 : nsBoxFrame(aPresShell, aContext),
michael@0 206 mInner(0)
michael@0 207 {
michael@0 208 }
michael@0 209
michael@0 210 void
michael@0 211 nsSplitterFrame::DestroyFrom(nsIFrame* aDestructRoot)
michael@0 212 {
michael@0 213 if (mInner) {
michael@0 214 mInner->RemoveListener();
michael@0 215 mInner->Disconnect();
michael@0 216 mInner->Release();
michael@0 217 mInner = nullptr;
michael@0 218 }
michael@0 219 nsBoxFrame::DestroyFrom(aDestructRoot);
michael@0 220 }
michael@0 221
michael@0 222
michael@0 223 nsresult
michael@0 224 nsSplitterFrame::GetCursor(const nsPoint& aPoint,
michael@0 225 nsIFrame::Cursor& aCursor)
michael@0 226 {
michael@0 227 return nsBoxFrame::GetCursor(aPoint, aCursor);
michael@0 228
michael@0 229 /*
michael@0 230 if (IsHorizontal())
michael@0 231 aCursor = NS_STYLE_CURSOR_N_RESIZE;
michael@0 232 else
michael@0 233 aCursor = NS_STYLE_CURSOR_W_RESIZE;
michael@0 234
michael@0 235 return NS_OK;
michael@0 236 */
michael@0 237 }
michael@0 238
michael@0 239 nsresult
michael@0 240 nsSplitterFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 241 nsIAtom* aAttribute,
michael@0 242 int32_t aModType)
michael@0 243 {
michael@0 244 nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
michael@0 245 aModType);
michael@0 246 // if the alignment changed. Let the grippy know
michael@0 247 if (aAttribute == nsGkAtoms::align) {
michael@0 248 // tell the slider its attribute changed so it can
michael@0 249 // update itself
michael@0 250 nsIFrame* grippy = nullptr;
michael@0 251 nsScrollbarButtonFrame::GetChildWithTag(PresContext(), nsGkAtoms::grippy, this, grippy);
michael@0 252 if (grippy)
michael@0 253 grippy->AttributeChanged(aNameSpaceID, aAttribute, aModType);
michael@0 254 } else if (aAttribute == nsGkAtoms::state) {
michael@0 255 mInner->UpdateState();
michael@0 256 }
michael@0 257
michael@0 258 return rv;
michael@0 259 }
michael@0 260
michael@0 261 /**
michael@0 262 * Initialize us. If we are in a box get our alignment so we know what direction we are
michael@0 263 */
michael@0 264 void
michael@0 265 nsSplitterFrame::Init(nsIContent* aContent,
michael@0 266 nsIFrame* aParent,
michael@0 267 nsIFrame* aPrevInFlow)
michael@0 268 {
michael@0 269 MOZ_ASSERT(!mInner);
michael@0 270 mInner = new nsSplitterFrameInner(this);
michael@0 271
michael@0 272 mInner->AddRef();
michael@0 273 mInner->mChildInfosAfter = nullptr;
michael@0 274 mInner->mChildInfosBefore = nullptr;
michael@0 275 mInner->mState = nsSplitterFrameInner::Open;
michael@0 276 mInner->mDragging = false;
michael@0 277
michael@0 278 // determine orientation of parent, and if vertical, set orient to vertical
michael@0 279 // on splitter content, then re-resolve style
michael@0 280 // XXXbz this is pretty messed up, since this can change whether we should
michael@0 281 // have a frame at all. This really needs a better solution.
michael@0 282 if (aParent && aParent->IsBoxFrame()) {
michael@0 283 if (!aParent->IsHorizontal()) {
michael@0 284 if (!nsContentUtils::HasNonEmptyAttr(aContent, kNameSpaceID_None,
michael@0 285 nsGkAtoms::orient)) {
michael@0 286 aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orient,
michael@0 287 NS_LITERAL_STRING("vertical"), false);
michael@0 288 nsStyleContext* parentStyleContext = StyleContext()->GetParent();
michael@0 289 nsRefPtr<nsStyleContext> newContext = PresContext()->StyleSet()->
michael@0 290 ResolveStyleFor(aContent->AsElement(), parentStyleContext);
michael@0 291 SetStyleContextWithoutNotification(newContext);
michael@0 292 }
michael@0 293 }
michael@0 294 }
michael@0 295
michael@0 296 nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
michael@0 297
michael@0 298 mInner->mState = nsSplitterFrameInner::Open;
michael@0 299 mInner->AddListener(PresContext());
michael@0 300 mInner->mParentBox = nullptr;
michael@0 301 }
michael@0 302
michael@0 303 NS_IMETHODIMP
michael@0 304 nsSplitterFrame::DoLayout(nsBoxLayoutState& aState)
michael@0 305 {
michael@0 306 if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
michael@0 307 {
michael@0 308 mInner->mParentBox = GetParentBox();
michael@0 309 mInner->UpdateState();
michael@0 310 }
michael@0 311
michael@0 312 return nsBoxFrame::DoLayout(aState);
michael@0 313 }
michael@0 314
michael@0 315
michael@0 316 void
michael@0 317 nsSplitterFrame::GetInitialOrientation(bool& aIsHorizontal)
michael@0 318 {
michael@0 319 nsIFrame* box = GetParentBox();
michael@0 320 if (box) {
michael@0 321 aIsHorizontal = !box->IsHorizontal();
michael@0 322 }
michael@0 323 else
michael@0 324 nsBoxFrame::GetInitialOrientation(aIsHorizontal);
michael@0 325 }
michael@0 326
michael@0 327 NS_IMETHODIMP
michael@0 328 nsSplitterFrame::HandlePress(nsPresContext* aPresContext,
michael@0 329 WidgetGUIEvent* aEvent,
michael@0 330 nsEventStatus* aEventStatus)
michael@0 331 {
michael@0 332 return NS_OK;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMETHODIMP
michael@0 336 nsSplitterFrame::HandleMultiplePress(nsPresContext* aPresContext,
michael@0 337 WidgetGUIEvent* aEvent,
michael@0 338 nsEventStatus* aEventStatus,
michael@0 339 bool aControlHeld)
michael@0 340 {
michael@0 341 return NS_OK;
michael@0 342 }
michael@0 343
michael@0 344 NS_IMETHODIMP
michael@0 345 nsSplitterFrame::HandleDrag(nsPresContext* aPresContext,
michael@0 346 WidgetGUIEvent* aEvent,
michael@0 347 nsEventStatus* aEventStatus)
michael@0 348 {
michael@0 349 return NS_OK;
michael@0 350 }
michael@0 351
michael@0 352 NS_IMETHODIMP
michael@0 353 nsSplitterFrame::HandleRelease(nsPresContext* aPresContext,
michael@0 354 WidgetGUIEvent* aEvent,
michael@0 355 nsEventStatus* aEventStatus)
michael@0 356 {
michael@0 357 return NS_OK;
michael@0 358 }
michael@0 359
michael@0 360 void
michael@0 361 nsSplitterFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 362 const nsRect& aDirtyRect,
michael@0 363 const nsDisplayListSet& aLists)
michael@0 364 {
michael@0 365 nsBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
michael@0 366
michael@0 367 // if the mouse is captured always return us as the frame.
michael@0 368 if (mInner->mDragging)
michael@0 369 {
michael@0 370 // XXX It's probably better not to check visibility here, right?
michael@0 371 aLists.Outlines()->AppendNewToTop(new (aBuilder)
michael@0 372 nsDisplayEventReceiver(aBuilder, this));
michael@0 373 return;
michael@0 374 }
michael@0 375 }
michael@0 376
michael@0 377 nsresult
michael@0 378 nsSplitterFrame::HandleEvent(nsPresContext* aPresContext,
michael@0 379 WidgetGUIEvent* aEvent,
michael@0 380 nsEventStatus* aEventStatus)
michael@0 381 {
michael@0 382 NS_ENSURE_ARG_POINTER(aEventStatus);
michael@0 383 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
michael@0 384 return NS_OK;
michael@0 385 }
michael@0 386
michael@0 387 nsWeakFrame weakFrame(this);
michael@0 388 nsRefPtr<nsSplitterFrameInner> kungFuDeathGrip(mInner);
michael@0 389 switch (aEvent->message) {
michael@0 390 case NS_MOUSE_MOVE:
michael@0 391 mInner->MouseDrag(aPresContext, aEvent);
michael@0 392 break;
michael@0 393
michael@0 394 case NS_MOUSE_BUTTON_UP:
michael@0 395 if (aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
michael@0 396 mInner->MouseUp(aPresContext, aEvent);
michael@0 397 }
michael@0 398 break;
michael@0 399 }
michael@0 400
michael@0 401 NS_ENSURE_STATE(weakFrame.IsAlive());
michael@0 402 return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
michael@0 403 }
michael@0 404
michael@0 405 void
michael@0 406 nsSplitterFrameInner::MouseUp(nsPresContext* aPresContext,
michael@0 407 WidgetGUIEvent* aEvent)
michael@0 408 {
michael@0 409 if (mDragging && mOuter) {
michael@0 410 AdjustChildren(aPresContext);
michael@0 411 AddListener(aPresContext);
michael@0 412 nsIPresShell::SetCapturingContent(nullptr, 0); // XXXndeakin is this needed?
michael@0 413 mDragging = false;
michael@0 414 State newState = GetState();
michael@0 415 // if the state is dragging then make it Open.
michael@0 416 if (newState == Dragging)
michael@0 417 mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, EmptyString(), true);
michael@0 418
michael@0 419 mPressed = false;
michael@0 420
michael@0 421 // if we dragged then fire a command event.
michael@0 422 if (mDidDrag) {
michael@0 423 nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(mOuter->GetContent());
michael@0 424 element->DoCommand();
michael@0 425 }
michael@0 426
michael@0 427 //printf("MouseUp\n");
michael@0 428 }
michael@0 429
michael@0 430 delete[] mChildInfosBefore;
michael@0 431 delete[] mChildInfosAfter;
michael@0 432 mChildInfosBefore = nullptr;
michael@0 433 mChildInfosAfter = nullptr;
michael@0 434 mChildInfosBeforeCount = 0;
michael@0 435 mChildInfosAfterCount = 0;
michael@0 436 }
michael@0 437
michael@0 438 void
michael@0 439 nsSplitterFrameInner::MouseDrag(nsPresContext* aPresContext,
michael@0 440 WidgetGUIEvent* aEvent)
michael@0 441 {
michael@0 442 if (mDragging && mOuter) {
michael@0 443
michael@0 444 //printf("Dragging\n");
michael@0 445
michael@0 446 bool isHorizontal = !mOuter->IsHorizontal();
michael@0 447 // convert coord to pixels
michael@0 448 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
michael@0 449 mParentBox);
michael@0 450 nscoord pos = isHorizontal ? pt.x : pt.y;
michael@0 451
michael@0 452 // mDragStart is in frame coordinates
michael@0 453 nscoord start = mDragStart;
michael@0 454
michael@0 455 // take our current position and subtract the start location
michael@0 456 pos -= start;
michael@0 457
michael@0 458 //printf("Diff=%d\n", pos);
michael@0 459
michael@0 460 ResizeType resizeAfter = GetResizeAfter();
michael@0 461
michael@0 462 bool bounded;
michael@0 463
michael@0 464 if (resizeAfter == nsSplitterFrameInner::Grow)
michael@0 465 bounded = false;
michael@0 466 else
michael@0 467 bounded = true;
michael@0 468
michael@0 469 int i;
michael@0 470 for (i=0; i < mChildInfosBeforeCount; i++)
michael@0 471 mChildInfosBefore[i].changed = mChildInfosBefore[i].current;
michael@0 472
michael@0 473 for (i=0; i < mChildInfosAfterCount; i++)
michael@0 474 mChildInfosAfter[i].changed = mChildInfosAfter[i].current;
michael@0 475
michael@0 476 nscoord oldPos = pos;
michael@0 477
michael@0 478 ResizeChildTo(aPresContext, pos, mChildInfosBefore, mChildInfosAfter, mChildInfosBeforeCount, mChildInfosAfterCount, bounded);
michael@0 479
michael@0 480 State currentState = GetState();
michael@0 481 bool supportsBefore = SupportsCollapseDirection(Before);
michael@0 482 bool supportsAfter = SupportsCollapseDirection(After);
michael@0 483
michael@0 484 const bool isRTL = mOuter->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
michael@0 485 bool pastEnd = oldPos > 0 && oldPos > pos;
michael@0 486 bool pastBegin = oldPos < 0 && oldPos < pos;
michael@0 487 if (isRTL) {
michael@0 488 // Swap the boundary checks in RTL mode
michael@0 489 bool tmp = pastEnd;
michael@0 490 pastEnd = pastBegin;
michael@0 491 pastBegin = tmp;
michael@0 492 }
michael@0 493 const bool isCollapsedBefore = pastBegin && supportsBefore;
michael@0 494 const bool isCollapsedAfter = pastEnd && supportsAfter;
michael@0 495
michael@0 496 // if we are in a collapsed position
michael@0 497 if (isCollapsedBefore || isCollapsedAfter)
michael@0 498 {
michael@0 499 // and we are not collapsed then collapse
michael@0 500 if (currentState == Dragging) {
michael@0 501 if (pastEnd)
michael@0 502 {
michael@0 503 //printf("Collapse right\n");
michael@0 504 if (supportsAfter)
michael@0 505 {
michael@0 506 nsCOMPtr<nsIContent> outer = mOuter->mContent;
michael@0 507 outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate,
michael@0 508 NS_LITERAL_STRING("after"),
michael@0 509 true);
michael@0 510 outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
michael@0 511 NS_LITERAL_STRING("collapsed"),
michael@0 512 true);
michael@0 513 }
michael@0 514
michael@0 515 } else if (pastBegin)
michael@0 516 {
michael@0 517 //printf("Collapse left\n");
michael@0 518 if (supportsBefore)
michael@0 519 {
michael@0 520 nsCOMPtr<nsIContent> outer = mOuter->mContent;
michael@0 521 outer->SetAttr(kNameSpaceID_None, nsGkAtoms::substate,
michael@0 522 NS_LITERAL_STRING("before"),
michael@0 523 true);
michael@0 524 outer->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
michael@0 525 NS_LITERAL_STRING("collapsed"),
michael@0 526 true);
michael@0 527 }
michael@0 528 }
michael@0 529 }
michael@0 530 } else {
michael@0 531 // if we are not in a collapsed position and we are not dragging make sure
michael@0 532 // we are dragging.
michael@0 533 if (currentState != Dragging)
michael@0 534 mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state, NS_LITERAL_STRING("dragging"), true);
michael@0 535 AdjustChildren(aPresContext);
michael@0 536 }
michael@0 537
michael@0 538 mDidDrag = true;
michael@0 539 }
michael@0 540 }
michael@0 541
michael@0 542 void
michael@0 543 nsSplitterFrameInner::AddListener(nsPresContext* aPresContext)
michael@0 544 {
michael@0 545 mOuter->GetContent()->
michael@0 546 AddEventListener(NS_LITERAL_STRING("mouseup"), this, false, false);
michael@0 547 mOuter->GetContent()->
michael@0 548 AddEventListener(NS_LITERAL_STRING("mousedown"), this, false, false);
michael@0 549 mOuter->GetContent()->
michael@0 550 AddEventListener(NS_LITERAL_STRING("mousemove"), this, false, false);
michael@0 551 mOuter->GetContent()->
michael@0 552 AddEventListener(NS_LITERAL_STRING("mouseout"), this, false, false);
michael@0 553 }
michael@0 554
michael@0 555 void
michael@0 556 nsSplitterFrameInner::RemoveListener()
michael@0 557 {
michael@0 558 ENSURE_TRUE(mOuter);
michael@0 559 mOuter->GetContent()->
michael@0 560 RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, false);
michael@0 561 mOuter->GetContent()->
michael@0 562 RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, false);
michael@0 563 mOuter->GetContent()->
michael@0 564 RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, false);
michael@0 565 mOuter->GetContent()->
michael@0 566 RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, false);
michael@0 567 }
michael@0 568
michael@0 569 nsresult
michael@0 570 nsSplitterFrameInner::HandleEvent(nsIDOMEvent* aEvent)
michael@0 571 {
michael@0 572 nsAutoString eventType;
michael@0 573 aEvent->GetType(eventType);
michael@0 574 if (eventType.EqualsLiteral("mouseup"))
michael@0 575 return MouseUp(aEvent);
michael@0 576 if (eventType.EqualsLiteral("mousedown"))
michael@0 577 return MouseDown(aEvent);
michael@0 578 if (eventType.EqualsLiteral("mousemove") ||
michael@0 579 eventType.EqualsLiteral("mouseout"))
michael@0 580 return MouseMove(aEvent);
michael@0 581
michael@0 582 NS_ABORT();
michael@0 583 return NS_OK;
michael@0 584 }
michael@0 585
michael@0 586 nsresult
michael@0 587 nsSplitterFrameInner::MouseUp(nsIDOMEvent* aMouseEvent)
michael@0 588 {
michael@0 589 NS_ENSURE_TRUE(mOuter, NS_OK);
michael@0 590 mPressed = false;
michael@0 591
michael@0 592 nsIPresShell::SetCapturingContent(nullptr, 0);
michael@0 593
michael@0 594 return NS_OK;
michael@0 595 }
michael@0 596
michael@0 597 nsresult
michael@0 598 nsSplitterFrameInner::MouseDown(nsIDOMEvent* aMouseEvent)
michael@0 599 {
michael@0 600 NS_ENSURE_TRUE(mOuter, NS_OK);
michael@0 601 nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent));
michael@0 602 if (!mouseEvent)
michael@0 603 return NS_OK;
michael@0 604
michael@0 605 int16_t button = 0;
michael@0 606 mouseEvent->GetButton(&button);
michael@0 607
michael@0 608 // only if left button
michael@0 609 if (button != 0)
michael@0 610 return NS_OK;
michael@0 611
michael@0 612 if (mOuter->GetContent()->
michael@0 613 AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
michael@0 614 nsGkAtoms::_true, eCaseMatters))
michael@0 615 return NS_OK;
michael@0 616
michael@0 617 mParentBox = mOuter->GetParentBox();
michael@0 618 if (!mParentBox)
michael@0 619 return NS_OK;
michael@0 620
michael@0 621 // get our index
michael@0 622 nsPresContext* outerPresContext = mOuter->PresContext();
michael@0 623 const nsFrameList& siblingList(mParentBox->PrincipalChildList());
michael@0 624 int32_t childIndex = siblingList.IndexOf(mOuter);
michael@0 625 // if it's 0 (or not found) then stop right here.
michael@0 626 // It might be not found if we're not in the parent's primary frame list.
michael@0 627 if (childIndex <= 0)
michael@0 628 return NS_OK;
michael@0 629
michael@0 630 int32_t childCount = siblingList.GetLength();
michael@0 631 // if it's the last index then we need to allow for resizeafter="grow"
michael@0 632 if (childIndex == childCount - 1 && GetResizeAfter() != Grow)
michael@0 633 return NS_OK;
michael@0 634
michael@0 635 nsRefPtr<nsRenderingContext> rc =
michael@0 636 outerPresContext->PresShell()->CreateReferenceRenderingContext();
michael@0 637 nsBoxLayoutState state(outerPresContext, rc);
michael@0 638 mCurrentPos = 0;
michael@0 639 mPressed = true;
michael@0 640
michael@0 641 mDidDrag = false;
michael@0 642
michael@0 643 EnsureOrient();
michael@0 644 bool isHorizontal = !mOuter->IsHorizontal();
michael@0 645
michael@0 646 ResizeType resizeBefore = GetResizeBefore();
michael@0 647 ResizeType resizeAfter = GetResizeAfter();
michael@0 648
michael@0 649 delete[] mChildInfosBefore;
michael@0 650 delete[] mChildInfosAfter;
michael@0 651 mChildInfosBefore = new nsSplitterInfo[childCount];
michael@0 652 mChildInfosAfter = new nsSplitterInfo[childCount];
michael@0 653
michael@0 654 // create info 2 lists. One of the children before us and one after.
michael@0 655 int32_t count = 0;
michael@0 656 mChildInfosBeforeCount = 0;
michael@0 657 mChildInfosAfterCount = 0;
michael@0 658
michael@0 659 nsIFrame* childBox = mParentBox->GetChildBox();
michael@0 660
michael@0 661 while (nullptr != childBox)
michael@0 662 {
michael@0 663 nsIContent* content = childBox->GetContent();
michael@0 664 nsIDocument* doc = content->OwnerDoc();
michael@0 665 int32_t dummy;
michael@0 666 nsIAtom* atom = doc->BindingManager()->ResolveTag(content, &dummy);
michael@0 667
michael@0 668 // skip over any splitters
michael@0 669 if (atom != nsGkAtoms::splitter) {
michael@0 670 nsSize prefSize = childBox->GetPrefSize(state);
michael@0 671 nsSize minSize = childBox->GetMinSize(state);
michael@0 672 nsSize maxSize = nsBox::BoundsCheckMinMax(minSize, childBox->GetMaxSize(state));
michael@0 673 prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize);
michael@0 674
michael@0 675 mOuter->AddMargin(childBox, minSize);
michael@0 676 mOuter->AddMargin(childBox, prefSize);
michael@0 677 mOuter->AddMargin(childBox, maxSize);
michael@0 678
michael@0 679 nscoord flex = childBox->GetFlex(state);
michael@0 680
michael@0 681 nsMargin margin(0,0,0,0);
michael@0 682 childBox->GetMargin(margin);
michael@0 683 nsRect r(childBox->GetRect());
michael@0 684 r.Inflate(margin);
michael@0 685
michael@0 686 // We need to check for hidden attribute too, since treecols with
michael@0 687 // the hidden="true" attribute are not really hidden, just collapsed
michael@0 688 if (!content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::fixed,
michael@0 689 nsGkAtoms::_true, eCaseMatters) &&
michael@0 690 !content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
michael@0 691 nsGkAtoms::_true, eCaseMatters)) {
michael@0 692 if (count < childIndex && (resizeBefore != Flex || flex > 0)) {
michael@0 693 mChildInfosBefore[mChildInfosBeforeCount].childElem = content;
michael@0 694 mChildInfosBefore[mChildInfosBeforeCount].min = isHorizontal ? minSize.width : minSize.height;
michael@0 695 mChildInfosBefore[mChildInfosBeforeCount].max = isHorizontal ? maxSize.width : maxSize.height;
michael@0 696 mChildInfosBefore[mChildInfosBeforeCount].current = isHorizontal ? r.width : r.height;
michael@0 697 mChildInfosBefore[mChildInfosBeforeCount].flex = flex;
michael@0 698 mChildInfosBefore[mChildInfosBeforeCount].index = count;
michael@0 699 mChildInfosBefore[mChildInfosBeforeCount].changed = mChildInfosBefore[mChildInfosBeforeCount].current;
michael@0 700 mChildInfosBeforeCount++;
michael@0 701 } else if (count > childIndex && (resizeAfter != Flex || flex > 0)) {
michael@0 702 mChildInfosAfter[mChildInfosAfterCount].childElem = content;
michael@0 703 mChildInfosAfter[mChildInfosAfterCount].min = isHorizontal ? minSize.width : minSize.height;
michael@0 704 mChildInfosAfter[mChildInfosAfterCount].max = isHorizontal ? maxSize.width : maxSize.height;
michael@0 705 mChildInfosAfter[mChildInfosAfterCount].current = isHorizontal ? r.width : r.height;
michael@0 706 mChildInfosAfter[mChildInfosAfterCount].flex = flex;
michael@0 707 mChildInfosAfter[mChildInfosAfterCount].index = count;
michael@0 708 mChildInfosAfter[mChildInfosAfterCount].changed = mChildInfosAfter[mChildInfosAfterCount].current;
michael@0 709 mChildInfosAfterCount++;
michael@0 710 }
michael@0 711 }
michael@0 712 }
michael@0 713
michael@0 714 childBox = childBox->GetNextBox();
michael@0 715 count++;
michael@0 716 }
michael@0 717
michael@0 718 if (!mParentBox->IsNormalDirection()) {
michael@0 719 // The before array is really the after array, and the order needs to be reversed.
michael@0 720 // First reverse both arrays.
michael@0 721 Reverse(mChildInfosBefore, mChildInfosBeforeCount);
michael@0 722 Reverse(mChildInfosAfter, mChildInfosAfterCount);
michael@0 723
michael@0 724 // Now swap the two arrays.
michael@0 725 nscoord newAfterCount = mChildInfosBeforeCount;
michael@0 726 mChildInfosBeforeCount = mChildInfosAfterCount;
michael@0 727 mChildInfosAfterCount = newAfterCount;
michael@0 728 nsSplitterInfo* temp = mChildInfosAfter;
michael@0 729 mChildInfosAfter = mChildInfosBefore;
michael@0 730 mChildInfosBefore = temp;
michael@0 731 }
michael@0 732
michael@0 733 // if resizebefore is not Farthest, reverse the list because the first child
michael@0 734 // in the list is the farthest, and we want the first child to be the closest.
michael@0 735 if (resizeBefore != Farthest)
michael@0 736 Reverse(mChildInfosBefore, mChildInfosBeforeCount);
michael@0 737
michael@0 738 // if the resizeafter is the Farthest we must reverse the list because the first child in the list
michael@0 739 // is the closest we want the first child to be the Farthest.
michael@0 740 if (resizeAfter == Farthest)
michael@0 741 Reverse(mChildInfosAfter, mChildInfosAfterCount);
michael@0 742
michael@0 743 // grow only applys to the children after. If grow is set then no space should be taken out of any children after
michael@0 744 // us. To do this we just set the size of that list to be 0.
michael@0 745 if (resizeAfter == Grow)
michael@0 746 mChildInfosAfterCount = 0;
michael@0 747
michael@0 748 int32_t c;
michael@0 749 nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent,
michael@0 750 mParentBox);
michael@0 751 if (isHorizontal) {
michael@0 752 c = pt.x;
michael@0 753 mSplitterPos = mOuter->mRect.x;
michael@0 754 } else {
michael@0 755 c = pt.y;
michael@0 756 mSplitterPos = mOuter->mRect.y;
michael@0 757 }
michael@0 758
michael@0 759 mDragStart = c;
michael@0 760
michael@0 761 //printf("Pressed mDragStart=%d\n",mDragStart);
michael@0 762
michael@0 763 nsIPresShell::SetCapturingContent(mOuter->GetContent(), CAPTURE_IGNOREALLOWED);
michael@0 764
michael@0 765 return NS_OK;
michael@0 766 }
michael@0 767
michael@0 768 nsresult
michael@0 769 nsSplitterFrameInner::MouseMove(nsIDOMEvent* aMouseEvent)
michael@0 770 {
michael@0 771 NS_ENSURE_TRUE(mOuter, NS_OK);
michael@0 772 if (!mPressed)
michael@0 773 return NS_OK;
michael@0 774
michael@0 775 if (mDragging)
michael@0 776 return NS_OK;
michael@0 777
michael@0 778 nsCOMPtr<nsIDOMEventListener> kungfuDeathGrip(this);
michael@0 779 mOuter->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::state,
michael@0 780 NS_LITERAL_STRING("dragging"), true);
michael@0 781
michael@0 782 RemoveListener();
michael@0 783 mDragging = true;
michael@0 784
michael@0 785 return NS_OK;
michael@0 786 }
michael@0 787
michael@0 788 void
michael@0 789 nsSplitterFrameInner::Reverse(nsSplitterInfo*& aChildInfos, int32_t aCount)
michael@0 790 {
michael@0 791 nsSplitterInfo* infos = new nsSplitterInfo[aCount];
michael@0 792
michael@0 793 for (int i=0; i < aCount; i++)
michael@0 794 infos[i] = aChildInfos[aCount - 1 - i];
michael@0 795
michael@0 796 delete[] aChildInfos;
michael@0 797 aChildInfos = infos;
michael@0 798 }
michael@0 799
michael@0 800 bool
michael@0 801 nsSplitterFrameInner::SupportsCollapseDirection
michael@0 802 (
michael@0 803 nsSplitterFrameInner::CollapseDirection aDirection
michael@0 804 )
michael@0 805 {
michael@0 806 static nsIContent::AttrValuesArray strings[] =
michael@0 807 {&nsGkAtoms::before, &nsGkAtoms::after, &nsGkAtoms::both, nullptr};
michael@0 808
michael@0 809 switch (mOuter->mContent->FindAttrValueIn(kNameSpaceID_None,
michael@0 810 nsGkAtoms::collapse,
michael@0 811 strings, eCaseMatters)) {
michael@0 812 case 0:
michael@0 813 return (aDirection == Before);
michael@0 814 case 1:
michael@0 815 return (aDirection == After);
michael@0 816 case 2:
michael@0 817 return true;
michael@0 818 }
michael@0 819
michael@0 820 return false;
michael@0 821 }
michael@0 822
michael@0 823 void
michael@0 824 nsSplitterFrameInner::UpdateState()
michael@0 825 {
michael@0 826 // State Transitions:
michael@0 827 // Open -> Dragging
michael@0 828 // Open -> CollapsedBefore
michael@0 829 // Open -> CollapsedAfter
michael@0 830 // CollapsedBefore -> Open
michael@0 831 // CollapsedBefore -> Dragging
michael@0 832 // CollapsedAfter -> Open
michael@0 833 // CollapsedAfter -> Dragging
michael@0 834 // Dragging -> Open
michael@0 835 // Dragging -> CollapsedBefore (auto collapse)
michael@0 836 // Dragging -> CollapsedAfter (auto collapse)
michael@0 837
michael@0 838 State newState = GetState();
michael@0 839
michael@0 840 if (newState == mState) {
michael@0 841 // No change.
michael@0 842 return;
michael@0 843 }
michael@0 844
michael@0 845 if ((SupportsCollapseDirection(Before) || SupportsCollapseDirection(After)) &&
michael@0 846 mOuter->GetParent()->IsBoxFrame()) {
michael@0 847 // Find the splitter's immediate sibling.
michael@0 848 nsIFrame* splitterSibling;
michael@0 849 if (newState == CollapsedBefore || mState == CollapsedBefore) {
michael@0 850 splitterSibling = mOuter->GetPrevSibling();
michael@0 851 } else {
michael@0 852 splitterSibling = mOuter->GetNextSibling();
michael@0 853 }
michael@0 854
michael@0 855 if (splitterSibling) {
michael@0 856 nsCOMPtr<nsIContent> sibling = splitterSibling->GetContent();
michael@0 857 if (sibling) {
michael@0 858 if (mState == CollapsedBefore || mState == CollapsedAfter) {
michael@0 859 // CollapsedBefore -> Open
michael@0 860 // CollapsedBefore -> Dragging
michael@0 861 // CollapsedAfter -> Open
michael@0 862 // CollapsedAfter -> Dragging
michael@0 863 nsContentUtils::AddScriptRunner(
michael@0 864 new nsUnsetAttrRunnable(sibling, nsGkAtoms::collapsed));
michael@0 865 } else if ((mState == Open || mState == Dragging)
michael@0 866 && (newState == CollapsedBefore ||
michael@0 867 newState == CollapsedAfter)) {
michael@0 868 // Open -> CollapsedBefore / CollapsedAfter
michael@0 869 // Dragging -> CollapsedBefore / CollapsedAfter
michael@0 870 nsContentUtils::AddScriptRunner(
michael@0 871 new nsSetAttrRunnable(sibling, nsGkAtoms::collapsed,
michael@0 872 NS_LITERAL_STRING("true")));
michael@0 873 }
michael@0 874 }
michael@0 875 }
michael@0 876 }
michael@0 877 mState = newState;
michael@0 878 }
michael@0 879
michael@0 880 void
michael@0 881 nsSplitterFrameInner::EnsureOrient()
michael@0 882 {
michael@0 883 bool isHorizontal = !(mParentBox->GetStateBits() & NS_STATE_IS_HORIZONTAL);
michael@0 884 if (isHorizontal)
michael@0 885 mOuter->mState |= NS_STATE_IS_HORIZONTAL;
michael@0 886 else
michael@0 887 mOuter->mState &= ~NS_STATE_IS_HORIZONTAL;
michael@0 888 }
michael@0 889
michael@0 890 void
michael@0 891 nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext)
michael@0 892 {
michael@0 893 EnsureOrient();
michael@0 894 bool isHorizontal = !mOuter->IsHorizontal();
michael@0 895
michael@0 896 AdjustChildren(aPresContext, mChildInfosBefore, mChildInfosBeforeCount, isHorizontal);
michael@0 897 AdjustChildren(aPresContext, mChildInfosAfter, mChildInfosAfterCount, isHorizontal);
michael@0 898 }
michael@0 899
michael@0 900 static nsIFrame* GetChildBoxForContent(nsIFrame* aParentBox, nsIContent* aContent)
michael@0 901 {
michael@0 902 nsIFrame* childBox = aParentBox->GetChildBox();
michael@0 903
michael@0 904 while (nullptr != childBox) {
michael@0 905 if (childBox->GetContent() == aContent) {
michael@0 906 return childBox;
michael@0 907 }
michael@0 908 childBox = childBox->GetNextBox();
michael@0 909 }
michael@0 910 return nullptr;
michael@0 911 }
michael@0 912
michael@0 913 void
michael@0 914 nsSplitterFrameInner::AdjustChildren(nsPresContext* aPresContext, nsSplitterInfo* aChildInfos, int32_t aCount, bool aIsHorizontal)
michael@0 915 {
michael@0 916 ///printf("------- AdjustChildren------\n");
michael@0 917
michael@0 918 nsBoxLayoutState state(aPresContext);
michael@0 919
michael@0 920 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 921
michael@0 922 // first set all the widths.
michael@0 923 nsIFrame* child = mOuter->GetChildBox();
michael@0 924 while(child)
michael@0 925 {
michael@0 926 SetPreferredSize(state, child, onePixel, aIsHorizontal, nullptr);
michael@0 927 child = child->GetNextBox();
michael@0 928 }
michael@0 929
michael@0 930 // now set our changed widths.
michael@0 931 for (int i=0; i < aCount; i++)
michael@0 932 {
michael@0 933 nscoord pref = aChildInfos[i].changed;
michael@0 934 nsIFrame* childBox = GetChildBoxForContent(mParentBox, aChildInfos[i].childElem);
michael@0 935
michael@0 936 if (childBox) {
michael@0 937 SetPreferredSize(state, childBox, onePixel, aIsHorizontal, &pref);
michael@0 938 }
michael@0 939 }
michael@0 940 }
michael@0 941
michael@0 942 void
michael@0 943 nsSplitterFrameInner::SetPreferredSize(nsBoxLayoutState& aState, nsIFrame* aChildBox, nscoord aOnePixel, bool aIsHorizontal, nscoord* aSize)
michael@0 944 {
michael@0 945 nsRect rect(aChildBox->GetRect());
michael@0 946 nscoord pref = 0;
michael@0 947
michael@0 948 if (!aSize)
michael@0 949 {
michael@0 950 if (aIsHorizontal)
michael@0 951 pref = rect.width;
michael@0 952 else
michael@0 953 pref = rect.height;
michael@0 954 } else {
michael@0 955 pref = *aSize;
michael@0 956 }
michael@0 957
michael@0 958 nsMargin margin(0,0,0,0);
michael@0 959 aChildBox->GetMargin(margin);
michael@0 960
michael@0 961 nsCOMPtr<nsIAtom> attribute;
michael@0 962
michael@0 963 if (aIsHorizontal) {
michael@0 964 pref -= (margin.left + margin.right);
michael@0 965 attribute = nsGkAtoms::width;
michael@0 966 } else {
michael@0 967 pref -= (margin.top + margin.bottom);
michael@0 968 attribute = nsGkAtoms::height;
michael@0 969 }
michael@0 970
michael@0 971 nsIContent* content = aChildBox->GetContent();
michael@0 972
michael@0 973 // set its preferred size.
michael@0 974 nsAutoString prefValue;
michael@0 975 prefValue.AppendInt(pref/aOnePixel);
michael@0 976 if (content->AttrValueIs(kNameSpaceID_None, attribute,
michael@0 977 prefValue, eCaseMatters))
michael@0 978 return;
michael@0 979
michael@0 980 nsWeakFrame weakBox(aChildBox);
michael@0 981 content->SetAttr(kNameSpaceID_None, attribute, prefValue, true);
michael@0 982 ENSURE_TRUE(weakBox.IsAlive());
michael@0 983 aState.PresShell()->FrameNeedsReflow(aChildBox, nsIPresShell::eStyleChange,
michael@0 984 NS_FRAME_IS_DIRTY);
michael@0 985 }
michael@0 986
michael@0 987
michael@0 988 void
michael@0 989 nsSplitterFrameInner::AddRemoveSpace(nscoord aDiff,
michael@0 990 nsSplitterInfo* aChildInfos,
michael@0 991 int32_t aCount,
michael@0 992 int32_t& aSpaceLeft)
michael@0 993 {
michael@0 994 aSpaceLeft = 0;
michael@0 995
michael@0 996 for (int i=0; i < aCount; i++) {
michael@0 997 nscoord min = aChildInfos[i].min;
michael@0 998 nscoord max = aChildInfos[i].max;
michael@0 999 nscoord& c = aChildInfos[i].changed;
michael@0 1000
michael@0 1001 // figure our how much space to add or remove
michael@0 1002 if (c + aDiff < min) {
michael@0 1003 aDiff += (c - min);
michael@0 1004 c = min;
michael@0 1005 } else if (c + aDiff > max) {
michael@0 1006 aDiff -= (max - c);
michael@0 1007 c = max;
michael@0 1008 } else {
michael@0 1009 c += aDiff;
michael@0 1010 aDiff = 0;
michael@0 1011 }
michael@0 1012
michael@0 1013 // there is not space left? We are done
michael@0 1014 if (aDiff == 0)
michael@0 1015 break;
michael@0 1016 }
michael@0 1017
michael@0 1018 aSpaceLeft = aDiff;
michael@0 1019 }
michael@0 1020
michael@0 1021 /**
michael@0 1022 * Ok if we want to resize a child we will know the actual size in pixels we want it to be.
michael@0 1023 * This is not the preferred size. But they only way we can change a child is my manipulating its
michael@0 1024 * preferred size. So give the actual pixel size this return method will return figure out the preferred
michael@0 1025 * size and set it.
michael@0 1026 */
michael@0 1027
michael@0 1028 void
michael@0 1029 nsSplitterFrameInner::ResizeChildTo(nsPresContext* aPresContext,
michael@0 1030 nscoord& aDiff,
michael@0 1031 nsSplitterInfo* aChildrenBeforeInfos,
michael@0 1032 nsSplitterInfo* aChildrenAfterInfos,
michael@0 1033 int32_t aChildrenBeforeCount,
michael@0 1034 int32_t aChildrenAfterCount,
michael@0 1035 bool aBounded)
michael@0 1036 {
michael@0 1037 nscoord spaceLeft;
michael@0 1038 AddRemoveSpace(aDiff, aChildrenBeforeInfos,aChildrenBeforeCount,spaceLeft);
michael@0 1039
michael@0 1040 // if there is any space left over remove it from the dif we were originally given
michael@0 1041 aDiff -= spaceLeft;
michael@0 1042 AddRemoveSpace(-aDiff, aChildrenAfterInfos,aChildrenAfterCount,spaceLeft);
michael@0 1043
michael@0 1044 if (spaceLeft != 0) {
michael@0 1045 if (aBounded) {
michael@0 1046 aDiff += spaceLeft;
michael@0 1047 AddRemoveSpace(spaceLeft, aChildrenBeforeInfos,aChildrenBeforeCount,spaceLeft);
michael@0 1048 } else {
michael@0 1049 spaceLeft = 0;
michael@0 1050 }
michael@0 1051 }
michael@0 1052 }

mercurial