From 5c9cf65939a3843c1820c5c555903b051bb11353 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 19:52:23 -0800 Subject: [PATCH 1/7] Allow AnchorLayouts to prevent overflow. This is useful to propagate the bounds into children. --- ext/native/ui/ui_screen.cpp | 4 +++- ext/native/ui/viewgroup.cpp | 21 +++++++++++++++++---- ext/native/ui/viewgroup.h | 8 +++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ext/native/ui/ui_screen.cpp b/ext/native/ui/ui_screen.cpp index a29a735edc..80eb405ced 100644 --- a/ext/native/ui/ui_screen.cpp +++ b/ext/native/ui/ui_screen.cpp @@ -195,7 +195,9 @@ void PopupScreen::CreateViews() { UIContext &dc = *screenManager()->getUIContext(); - root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + AnchorLayout *anchor = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); + anchor->Overflow(false); + root_ = anchor; float yres = screenManager()->getUIContext()->GetBounds().h; diff --git a/ext/native/ui/viewgroup.cpp b/ext/native/ui/viewgroup.cpp index f8ece69a2d..35987f8739 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/ext/native/ui/viewgroup.cpp @@ -859,6 +859,15 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec specW(UNSPECIFIED, 0.0f); MeasureSpec specH(UNSPECIFIED, 0.0f); + if (!overflow_) { + if (horiz.type != UNSPECIFIED) { + specW = MeasureSpec(AT_MOST, horiz.size); + } + if (vert.type != UNSPECIFIED) { + specH = MeasureSpec(AT_MOST, vert.size); + } + } + const AnchorLayoutParams *params = static_cast(views_[i]->GetLayoutParams()); if (!params->Is(LP_ANCHOR)) params = 0; if (params) { @@ -866,15 +875,19 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v height = params->height; if (!params->center) { - if (params->left >= 0 && params->right >= 0) { + if (params->left >= 0 && params->right >= 0) { width = measuredWidth_ - params->left - params->right; } - if (params->top >= 0 && params->bottom >= 0) { + if (params->top >= 0 && params->bottom >= 0) { height = measuredHeight_ - params->top - params->bottom; } } - specW = width < 0 ? MeasureSpec(UNSPECIFIED) : MeasureSpec(EXACTLY, width); - specH = height < 0 ? MeasureSpec(UNSPECIFIED) : MeasureSpec(EXACTLY, height); + if (width >= 0) { + specW = MeasureSpec(EXACTLY, width); + } + if (height >= 0) { + specH = MeasureSpec(EXACTLY, height); + } } views_[i]->Measure(dc, specW, specH); diff --git a/ext/native/ui/viewgroup.h b/ext/native/ui/viewgroup.h index d45cf2cadb..69c91862b6 100644 --- a/ext/native/ui/viewgroup.h +++ b/ext/native/ui/viewgroup.h @@ -115,10 +115,16 @@ public: class AnchorLayout : public ViewGroup { public: - AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams) {} + AnchorLayout(LayoutParams *layoutParams = 0) : ViewGroup(layoutParams), overflow_(true) {} void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; void Layout() override; + void Overflow(bool allow) { + overflow_ = allow; + } std::string Describe() const override { return "AnchorLayout: " + View::Describe(); } + +private: + bool overflow_; }; class LinearLayoutParams : public LayoutParams { From f64159a3f2096c0b188eafe69edfeeeba4588366 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 19:53:31 -0800 Subject: [PATCH 2/7] Respect AT_MOST when measuring ScrollViews. --- ext/native/ui/viewgroup.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ext/native/ui/viewgroup.cpp b/ext/native/ui/viewgroup.cpp index 35987f8739..74bb799e4c 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/ext/native/ui/viewgroup.cpp @@ -604,8 +604,17 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver views_[0]->Measure(dc, MeasureSpec(AT_MOST, measuredWidth_ - (margins.left + margins.right)), MeasureSpec(UNSPECIFIED)); MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_); } - if (orientation_ == ORIENT_VERTICAL && vert.type != EXACTLY && measuredHeight_ < views_[0]->GetBounds().h) - measuredHeight_ = views_[0]->GetBounds().h; + if (orientation_ == ORIENT_VERTICAL && vert.type != EXACTLY) { + if (measuredHeight_ < views_[0]->GetMeasuredHeight()) { + measuredHeight_ = views_[0]->GetMeasuredHeight(); + } + if (measuredHeight_ < views_[0]->GetBounds().h) { + measuredHeight_ = views_[0]->GetBounds().h; + } + if (vert.type == AT_MOST && measuredHeight_ > vert.size) { + measuredHeight_ = vert.size; + } + } } } From bf20b992ea0c6bafe32d86bb9a859172db655aaf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 20:43:54 -0800 Subject: [PATCH 3/7] Make some tab holders fill their parent width. This is really what we want, not WRAP_CONTENT. --- UI/MainScreen.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index e498e8b863..846d06c46c 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -706,7 +706,7 @@ void MainScreen::CreateViews() { Margins actionMenuMargins(0, 10, 10, 0); - TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64); + TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); tabHolder_ = leftColumn; leftColumn->SetClip(true); @@ -813,12 +813,12 @@ void MainScreen::CreateViews() { if (vertical) { root_ = new LinearLayout(ORIENT_VERTICAL); rightColumn->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); + leftColumn->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0)); root_->Add(rightColumn); root_->Add(leftColumn); } else { root_ = new LinearLayout(ORIENT_HORIZONTAL); - leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); + leftColumn->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0)); rightColumn->ReplaceLayoutParams(new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); root_->Add(leftColumn); root_->Add(rightColumn); @@ -1110,7 +1110,7 @@ void UmdReplaceScreen::CreateViews() { I18NCategory *mm = GetI18NCategory("MainMenu"); I18NCategory *di = GetI18NCategory("Dialog"); - TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(1.0)); + TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0)); leftColumn->SetClip(true); ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(270, FILL_PARENT, actionMenuMargins)); From e7f70ff8d0eef356698b9b920bb1bc2e3fac2b4b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 19:56:43 -0800 Subject: [PATCH 4/7] Handle weighted LinearLayout children better. This allows them to not stretch the parent completely, but still increase the size of the parent. --- ext/native/ui/viewgroup.cpp | 42 ++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/ext/native/ui/viewgroup.cpp b/ext/native/ui/viewgroup.cpp index 74bb799e4c..5d5a2e7f4c 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/ext/native/ui/viewgroup.cpp @@ -446,7 +446,15 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureBySpec(layoutParams_->width, weightZeroSum, horiz, &measuredWidth_); MeasureBySpec(layoutParams_->height, maxOther, vert, &measuredHeight_); - float unit = (measuredWidth_ - weightZeroSum) / weightSum; + // If we've got stretch, allow growing to fill the parent. + float allowedWidth = measuredWidth_; + if (horiz.type == AT_MOST && measuredWidth_ < horiz.size) { + allowedWidth = horiz.size; + } + + float unit = (allowedWidth - weightZeroSum) / weightSum; + float usedWidth = 0.0f; + // Redistribute the stretchy ones! and remeasure the children! for (size_t i = 0; i < views_.size(); i++) { if (views_[i]->GetVisibility() == V_GONE) @@ -463,15 +471,30 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec v = vert; if (v.type == UNSPECIFIED && measuredHeight_ != 0.0) v = MeasureSpec(AT_MOST, measuredHeight_); - views_[i]->Measure(dc, MeasureSpec(EXACTLY, unit * linLayoutParams->weight - marginSum), v - (float)(margins.top + margins.bottom)); + MeasureSpec h(AT_MOST, unit * linLayoutParams->weight - marginSum); + if (horiz.type == EXACTLY) { + h.type = EXACTLY; + } + views_[i]->Measure(dc, h, v - (float)(margins.top + margins.bottom)); + usedWidth += views_[i]->GetMeasuredWidth(); } } + + if (horiz.type == AT_MOST && measuredWidth_ < horiz.size) { + measuredWidth_ += usedWidth; + } } else { - //MeasureBySpec(layoutParams_->height, vert.type == UNSPECIFIED ? sum : weightZeroSum, vert, &measuredHeight_); MeasureBySpec(layoutParams_->height, weightZeroSum, vert, &measuredHeight_); MeasureBySpec(layoutParams_->width, maxOther, horiz, &measuredWidth_); - float unit = (measuredHeight_ - weightZeroSum) / weightSum; + // If we've got stretch, allow growing to fill the parent. + float allowedHeight = measuredHeight_; + if (vert.type == AT_MOST && measuredHeight_ < vert.size) { + allowedHeight = vert.size; + } + + float unit = (allowedHeight - weightZeroSum) / weightSum; + float usedHeight = 0.0f; // Redistribute the stretchy ones! and remeasure the children! for (size_t i = 0; i < views_.size(); i++) { @@ -489,9 +512,18 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v MeasureSpec h = horiz; if (h.type == UNSPECIFIED && measuredWidth_ != 0.0) h = MeasureSpec(AT_MOST, measuredWidth_); - views_[i]->Measure(dc, h - (float)(margins.left + margins.right), MeasureSpec(EXACTLY, unit * linLayoutParams->weight - marginSum)); + MeasureSpec v(AT_MOST, unit * linLayoutParams->weight - marginSum); + if (vert.type == EXACTLY) { + v.type = EXACTLY; + } + views_[i]->Measure(dc, h - (float)(margins.left + margins.right), v); + usedHeight += views_[i]->GetMeasuredHeight(); } } + + if (vert.type == AT_MOST && measuredWidth_ < vert.size) { + measuredHeight_ += usedHeight; + } } } From 85ad28d4cd151d9485a2fb86379efee0ec39d13e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 20:07:37 -0800 Subject: [PATCH 5/7] Prettify fake RTTI for layout params. Better not to make the RTTI/non-RTTI thing a problem in lots of places. --- ext/native/ui/view.h | 20 ++++++++++++++++++++ ext/native/ui/viewgroup.cpp | 30 ++++++++---------------------- ext/native/ui/viewgroup.h | 8 ++++++++ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/ext/native/ui/view.h b/ext/native/ui/view.h index 62926338d0..952e3d9c29 100644 --- a/ext/native/ui/view.h +++ b/ext/native/ui/view.h @@ -292,6 +292,26 @@ public: // Fake RTTI bool Is(LayoutParamsType type) const { return type_ == type; } + template + T *As() { + if (Is(T::StaticType())) { + return static_cast(this); + } + return nullptr; + } + + template + const T *As() const { + if (Is(T::StaticType())) { + return static_cast(this); + } + return nullptr; + } + + static LayoutParamsType StaticType() { + return LP_PLAIN; + } + private: LayoutParamsType type_; }; diff --git a/ext/native/ui/viewgroup.cpp b/ext/native/ui/viewgroup.cpp index 5d5a2e7f4c..21f37cb8c9 100644 --- a/ext/native/ui/viewgroup.cpp +++ b/ext/native/ui/viewgroup.cpp @@ -395,9 +395,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v continue; numVisible++; - const LayoutParams *layoutParams = views_[i]->GetLayoutParams(); - const LinearLayoutParams *linLayoutParams = static_cast(layoutParams); - if (!linLayoutParams->Is(LP_LINEAR)) linLayoutParams = 0; + const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As(); Margins margins = defaultMargins_; @@ -459,9 +457,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v for (size_t i = 0; i < views_.size(); i++) { if (views_[i]->GetVisibility() == V_GONE) continue; - const LayoutParams *layoutParams = views_[i]->GetLayoutParams(); - const LinearLayoutParams *linLayoutParams = static_cast(layoutParams); - if (!linLayoutParams->Is(LP_LINEAR)) linLayoutParams = 0; + const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; @@ -500,9 +496,7 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v for (size_t i = 0; i < views_.size(); i++) { if (views_[i]->GetVisibility() == V_GONE) continue; - const LayoutParams *layoutParams = views_[i]->GetLayoutParams(); - const LinearLayoutParams *linLayoutParams = static_cast(layoutParams); - if (!linLayoutParams->Is(LP_LINEAR)) linLayoutParams = 0; + const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As(); if (linLayoutParams && linLayoutParams->weight > 0.0f) { Margins margins = defaultMargins_; @@ -548,9 +542,7 @@ void LinearLayout::Layout() { if (views_[i]->GetVisibility() == V_GONE) continue; - const LayoutParams *layoutParams = views_[i]->GetLayoutParams(); - const LinearLayoutParams *linLayoutParams = static_cast(layoutParams); - if (!linLayoutParams->Is(LP_LINEAR)) linLayoutParams = 0; + const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As(); Gravity gravity = G_TOPLEFT; Margins margins = defaultMargins_; @@ -615,10 +607,7 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver // Respect margins Margins margins; if (views_.size()) { - const LinearLayoutParams *linLayoutParams = static_cast(views_[0]->GetLayoutParams()); - if (!linLayoutParams->Is(LP_LINEAR)) { - linLayoutParams = 0; - } + const LinearLayoutParams *linLayoutParams = views_[0]->GetLayoutParams()->As(); if (linLayoutParams) { margins = linLayoutParams->margins; } @@ -657,8 +646,7 @@ void ScrollView::Layout() { // Respect margins Margins margins; - const LinearLayoutParams *linLayoutParams = static_cast(views_[0]->GetLayoutParams()); - if (!linLayoutParams->Is(LP_LINEAR)) linLayoutParams = 0; + const LinearLayoutParams *linLayoutParams = views_[0]->GetLayoutParams()->As(); if (linLayoutParams) { margins = linLayoutParams->margins; } @@ -909,8 +897,7 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v } } - const AnchorLayoutParams *params = static_cast(views_[i]->GetLayoutParams()); - if (!params->Is(LP_ANCHOR)) params = 0; + const AnchorLayoutParams *params = views_[i]->GetLayoutParams()->As(); if (params) { width = params->width; height = params->height; @@ -937,8 +924,7 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v void AnchorLayout::Layout() { for (size_t i = 0; i < views_.size(); i++) { - const AnchorLayoutParams *params = static_cast(views_[i]->GetLayoutParams()); - if (!params->Is(LP_ANCHOR)) params = 0; + const AnchorLayoutParams *params = views_[i]->GetLayoutParams()->As(); Bounds vBounds; vBounds.w = views_[i]->GetMeasuredWidth(); diff --git a/ext/native/ui/viewgroup.h b/ext/native/ui/viewgroup.h index 69c91862b6..833c937ef4 100644 --- a/ext/native/ui/viewgroup.h +++ b/ext/native/ui/viewgroup.h @@ -111,6 +111,10 @@ public: // Set to NONE to not attach this edge to the container. float left, top, right, bottom; bool center; // If set, only two "sides" can be set, and they refer to the center, not the edge, of the view being layouted. + + static LayoutParamsType StaticType() { + return LP_ANCHOR; + } }; class AnchorLayout : public ViewGroup { @@ -152,6 +156,10 @@ public: bool HasMargins() const { return hasMargins_; } + static LayoutParamsType StaticType() { + return LP_LINEAR; + } + private: bool hasMargins_; }; From 8923bd46e7dfe0ab45f4bab5352550dca8f949b8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 20:45:18 -0800 Subject: [PATCH 6/7] Support AT_MOST for WRAP_CONTENT. --- ext/native/ui/view.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/native/ui/view.cpp b/ext/native/ui/view.cpp index 15d92bcb78..4ec1c965f3 100644 --- a/ext/native/ui/view.cpp +++ b/ext/native/ui/view.cpp @@ -95,8 +95,10 @@ bool IsFocusMovementEnabled() { void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) { *measured = sz; if (sz == WRAP_CONTENT) { - if (spec.type == UNSPECIFIED || spec.type == AT_MOST) + if (spec.type == UNSPECIFIED) *measured = contentWidth; + else if (spec.type == AT_MOST) + *measured = contentWidth < spec.size ? contentWidth : spec.size; else if (spec.type == EXACTLY) *measured = spec.size; } else if (sz == FILL_PARENT) { From 1624079345021bad4b3204b5ee4ba3b2d1c0d265 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 22 Dec 2015 20:46:31 -0800 Subject: [PATCH 7/7] Scroll the devtools when the window is small. This allows access to the other tools at 1x, and allows us to add more as necessary. --- UI/DevScreens.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 38fb9d3fb6..f6e530edc2 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -61,20 +61,26 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) { I18NCategory *dev = GetI18NCategory("Developer"); I18NCategory *sy = GetI18NCategory("System"); + ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f)); + LinearLayout *items = new LinearLayout(ORIENT_VERTICAL); + #if !defined(MOBILE_DEVICE) - parent->Add(new Choice(dev->T("Log View")))->OnClick.Handle(this, &DevMenu::OnLogView); + items->Add(new Choice(dev->T("Log View")))->OnClick.Handle(this, &DevMenu::OnLogView); #endif - parent->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DevMenu::OnLogConfig); - parent->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools); - parent->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare); - parent->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenu::OnShaderView); - parent->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame); - parent->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame); - parent->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug); + items->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DevMenu::OnLogConfig); + items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools); + items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare); + items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenu::OnShaderView); + items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame); + items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame); + items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug); #ifdef USE_PROFILER - parent->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), "")); + items->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), "")); #endif + scroll->Add(items); + parent->Add(scroll); + RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener(); if (ring) { ring->SetEnable(true);