Skip to content

Commit

Permalink
refactor dropdown layout (#622)
Browse files Browse the repository at this point in the history
* refactor dropdown layout

* show dropdown and dropdown menu with same size

* add scroll for dropdown menu, move the dropdown and balance to the same line on mobile

---------

Co-authored-by: bugjt <@bugjt>
  • Loading branch information
bugjt authored Sep 26, 2024
1 parent 0493db9 commit 8f9e5f5
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 165 deletions.
216 changes: 116 additions & 100 deletions ui/cryptomaterial/dropdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type DropDown struct {
shadow *Shadow
expandedViewAlignment layout.Direction

list *widget.List
scroll ListStyle

noSelectedItem DropDownItem

FontWeight font.Weight
Expand Down Expand Up @@ -132,8 +135,11 @@ func (t *Theme) DropdownWithCustomPos(items []DropDownItem, group uint, groupPos
padding: layout.Inset{Top: values.MarginPadding8, Bottom: values.MarginPadding8},
shadow: t.Shadow(),
CollapsedLayoutTextDirection: layout.W,
list: &widget.List{
List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle},
},
}

d.scroll = t.List(d.list)
d.revs = reversePos
d.expandedViewAlignment = layout.NW
d.ExpandedLayoutInset = layout.Inset{Left: unit.Dp(dropdownInset)}
Expand Down Expand Up @@ -316,55 +322,18 @@ func (d *DropDown) collapsedAndExpandedLayout(gtx C) D {
// expandedLayout computes dropdown layout when dropdown is opened.
func (d *DropDown) expandedLayout(gtx C) D {
m := op.Record(gtx.Ops)
gtx.Constraints.Max.Y = inf
d.layout(gtx, d.ExpandedLayoutInset, d.listItemLayout)
gtx.Constraints.Min.Y = gtx.Constraints.Max.Y
d.updateDropdownWidth(gtx, true)
d.updateDropdownBackground(true)
d.ExpandedLayoutInset.Layout(gtx, func(gtx C) D {
return d.linearLayout.Layout2(gtx, d.listItemLayout)
})
op.Defer(gtx.Ops, m.Stop())
return D{}
}

func (d *DropDown) layout(gtx C, pos layout.Inset, wdgt layout.Widget) D {
return pos.Layout(gtx, func(gtx C) D {
return layout.Stack{}.Layout(gtx,
layout.Stacked(func(gtx C) D {
if d.Width < 0 {
d.linearLayout.Width = int(d.Width)
} else if d.Width == 0 {
d.Width = defaultDropdownWidth(d.revs)
d.linearLayout.Width = gtx.Dp(d.Width)
} else {
d.linearLayout.Width = gtx.Dp(d.Width)
}

if d.expanded {
d.linearLayout.Background = d.theme.Color.Surface
d.linearLayout.Padding = d.padding
d.linearLayout.Shadow = d.shadow
} else {
if d.Background != nil {
d.linearLayout.Background = *d.Background
} else {
d.linearLayout.Background = d.theme.Color.Gray2
}
d.linearLayout.Padding = layout.Inset{}
d.linearLayout.Shadow = nil
}

if d.BorderWidth > 0 {
d.linearLayout.Border.Width = d.BorderWidth
}

if d.BorderColor != nil {
d.linearLayout.Border.Color = *d.BorderColor
}
return d.linearLayout.Layout2(gtx, wdgt)
}),
)
})
}

func (d *DropDown) listItemLayout(gtx C) D {
list := &layout.List{Axis: layout.Vertical}
return list.Layout(gtx, len(d.items), func(gtx C, index int) D {
return d.scroll.Layout(gtx, len(d.items), func(gtx C, index int) D {
if len(d.items) == 0 {
return D{}
}
Expand All @@ -383,8 +352,10 @@ func (d *DropDown) listItemLayout(gtx C) D {

// collapsedLayout computes dropdown layout when dropdown is closed.
func (d *DropDown) collapsedLayout(gtx C) D {
d.updateDropdownWidth(gtx, false)
d.updateDropdownBackground(false)
return d.collapsedLayoutInset.Layout(gtx, func(gtx C) D {
return d.drawLayout(gtx, func(gtx C) D {
return d.linearLayout.Layout2(gtx, func(gtx C) D {
var selectedItem DropDownItem
if len(d.items) > 0 && d.selectedIndex > -1 {
selectedItem = d.items[d.selectedIndex]
Expand Down Expand Up @@ -424,7 +395,7 @@ func (d *DropDown) itemLayout(gtx C, index int, clickable *Clickable, item *Drop
if item.Icon == nil {
return D{}
}
gtx.Constraints.Min.Y = item.getItemHeight(gtx)
gtx.Constraints.Min.Y = item.getItemSize(gtx, d).Y
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle, Spacing: layout.SpaceAround}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return layout.Inset{Right: values.MarginPadding5}.Layout(gtx, item.Icon.Layout24dp)
Expand All @@ -436,16 +407,7 @@ func (d *DropDown) itemLayout(gtx C, index int, clickable *Clickable, item *Drop
return item.DisplayFn(gtx)
}

return bodyLayout.Layout2(gtx, func(gtx C) D {
lbl := d.theme.Body2(item.Text)
lbl.MaxLines = 1
if !d.expanded && len(item.Text) > d.maxTextLeng {
lbl.Text = item.Text[:d.maxTextLeng-3 /* subtract space for the ellipsis */] + "..."
}
lbl.Font.Weight = d.FontWeight
lbl.TextSize = d.getTextSize(values.TextSize14)
return lbl.Layout(gtx)
})
return bodyLayout.Layout2(gtx, d.renderItemLabel(item.Text))
}),
layout.Rigid(func(gtx C) D {
if !item.PreventSelection {
Expand Down Expand Up @@ -480,49 +442,14 @@ func (d *DropDown) layoutActiveIcon(gtx C, item *DropDownItem, index int) D {
if d.expanded && d.SelectedItemIconColor != nil {
icon.Color = *d.SelectedItemIconColor
}
gtx.Constraints.Min.Y = item.getItemHeight(gtx)
gtx.Constraints.Min.Y = item.getItemSize(gtx, d).Y
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle, Spacing: layout.SpaceAround}.Layout(gtx,
layout.Rigid(func(gtx C) D {
return icon.Layout(gtx, values.MarginPadding20)
}),
)
}

// drawLayout wraps the page tx and sync section in a card layout
func (d *DropDown) drawLayout(gtx C, body layout.Widget) D {
if d.Width < 0 {
d.linearLayout.Width = int(d.Width)
} else if d.Width == 0 {
d.Width = defaultDropdownWidth(d.revs)
d.linearLayout.Width = gtx.Dp(d.Width)
} else {
d.linearLayout.Width = gtx.Dp(d.Width)
}
if d.expanded {
d.linearLayout.Background = d.theme.Color.Surface
d.linearLayout.Padding = d.padding
d.linearLayout.Shadow = d.shadow
} else {
if d.Background != nil {
d.linearLayout.Background = *d.Background
} else {
d.linearLayout.Background = d.theme.Color.Surface
}
d.linearLayout.Padding = layout.Inset{}
d.linearLayout.Shadow = nil
}

if d.BorderWidth > 0 {
d.linearLayout.Border.Width = d.BorderWidth
}

if d.BorderColor != nil {
d.linearLayout.Border.Color = *d.BorderColor
}

return d.linearLayout.Layout2(gtx, body)
}

// Reslice the dropdowns
func ResliceDropdown(dropdowns []*DropDown, indexToRemove int) []*DropDown {
return append(dropdowns[:indexToRemove], dropdowns[indexToRemove+1:]...)
Expand Down Expand Up @@ -560,14 +487,103 @@ func (d *DropDown) ItemsLen() int {
return len(d.items)
}

func (i *DropDownItem) getItemHeight(gtx C) int {
func (i *DropDownItem) getItemSize(gtx C, d *DropDown) image.Point {
tmpGtx := layout.Context{
Ops: new(op.Ops),
Constraints: gtx.Constraints,
Metric: gtx.Metric,
}
if i.DisplayFn != nil {
tmpGtx := layout.Context{
Ops: new(op.Ops),
Constraints: gtx.Constraints,
Metric: gtx.Metric,
return i.DisplayFn(tmpGtx).Size
}
return LinearLayout{
Width: MatchParent,
Height: WrapContent,
Padding: layout.Inset{Right: values.MarginPadding5},
Direction: layout.W,
}.Layout2(tmpGtx, d.renderItemLabel(i.Text)).Size
}

func (d *DropDown) renderItemLabel(text string) layout.Widget {
return func(gtx C) D {
lbl := d.theme.Body2(text)
lbl.MaxLines = 1
if !d.expanded && len(text) > d.maxTextLeng {
lbl.Text = text[:d.maxTextLeng-3 /* subtract space for the ellipsis */] + "..."
}
lbl.Font.Weight = d.FontWeight
lbl.TextSize = d.getTextSize(values.TextSize14)
return lbl.Layout(gtx)
}
}

func (d *DropDown) getCurrentSize(gtx C) image.Point {
var selectedItem DropDownItem
if len(d.items) > 0 && d.selectedIndex > -1 {
selectedItem = d.items[d.selectedIndex]
} else {
selectedItem = d.noSelectedItem
}
return selectedItem.getItemSize(gtx, d)
}

func (d *DropDown) getMaxWidth(gtx C) int {
maxWidth := 0
if len(d.items) > 0 {
for _, item := range d.items {
itemWidth := item.getItemSize(gtx, d).X
if itemWidth > maxWidth {
maxWidth = itemWidth
}
}
}
return maxWidth
}

func (d *DropDown) updateDropdownBackground(expanded bool) {
if expanded {
d.linearLayout.Background = d.theme.Color.Surface
d.linearLayout.Padding = d.padding
d.linearLayout.Shadow = d.shadow
} else {
if d.Background != nil {
d.linearLayout.Background = *d.Background
} else {
d.linearLayout.Background = d.theme.Color.Gray2
}
d.linearLayout.Padding = layout.Inset{}
d.linearLayout.Shadow = nil
}

if d.BorderWidth > 0 {
d.linearLayout.Border.Width = d.BorderWidth
}

if d.BorderColor != nil {
d.linearLayout.Border.Color = *d.BorderColor
}
}

func (d *DropDown) updateDropdownWidth(gtx C, expanded bool) {
switch d.Width {
case WrapContent:
width := 0
if expanded {
width = d.getMaxWidth(gtx)
} else {
width = d.getCurrentSize(gtx).X
}
if width > 0 {
d.linearLayout.Width = width + gtx.Dp(values.MarginPadding70)
} else {
d.linearLayout.Width = gtx.Dp(defaultDropdownWidth(d.revs))
}
return i.DisplayFn(tmpGtx).Size.Y
case MatchParent:
d.linearLayout.Width = MatchParent
case 0:
d.linearLayout.Width = gtx.Dp(defaultDropdownWidth(d.revs))
default:
d.linearLayout.Width = gtx.Dp(d.Width)

}
return 1
}
Loading

0 comments on commit 8f9e5f5

Please sign in to comment.