summaryrefslogtreecommitdiff
path: root/main/src/ui/java/de/blinkt/openvpn/views/MultiLineRadioGroup.java
blob: 8296a644093835ae5cfc1c6d1beb76e3d18bb631 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 * Copyright (c) 2012-2018 Arne Schwabe
 * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
 */

package de.blinkt.openvpn.views;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RadioGroup;

import java.util.HashMap;
import java.util.Map;

public class MultiLineRadioGroup extends RadioGroup {
    private Map<View, Rect> viewRectMap;

    public MultiLineRadioGroup(Context context) {
        this(context, null);
    }

    public MultiLineRadioGroup(Context context, AttributeSet attrs) {
        super(context, attrs);

        viewRectMap = new HashMap<View, Rect>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        int widthMeasurement = MeasureSpec.getSize(widthMeasureSpec);
        int heightMeasurement = MeasureSpec.getSize(heightMeasureSpec);
        switch (getOrientation()){
            case HORIZONTAL:
                heightMeasurement = findHorizontalHeight(widthMeasureSpec, heightMeasureSpec);
                break;
            case VERTICAL:
                widthMeasurement = findVerticalWidth(widthMeasureSpec, heightMeasureSpec);
                break;
        }
        setMeasuredDimension(widthMeasurement, heightMeasurement);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int count = getChildCount();
        for(int x=0; x < count; ++x) {
            View button = getChildAt(x);
            Rect dims = viewRectMap.get(button);
            button.layout(dims.left, dims.top, dims.right, dims.bottom);
        }
    }

    private int findHorizontalHeight(int widthMeasureSpec, int heightMeasureSpec){
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        int maxRight = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight();

        // create MeasureSpecs to accommodate max space that RadioButtons can occupy
        int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxRight - getPaddingLeft(),
                MeasureSpec.getMode(widthMeasureSpec));
        int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                parentHeight - (getPaddingTop() + getPaddingBottom()),
                MeasureSpec.getMode(heightMeasureSpec));

        int nextLeft = getPaddingLeft();
        int nextTop = getPaddingTop();
        int maxRowHeight = 0;
        viewRectMap.clear();
        // measure and find placement for each RadioButton (results to be used in onLayout() stage)
        int count = getChildCount();
        for(int x=0; x < count; ++x){
            View button = getChildAt(x);
            measureChild(button, newWidthMeasureSpec, newHeightMeasureSpec);

            maxRowHeight = Math.max(maxRowHeight, button.getMeasuredHeight());

            // determine RadioButton placement
            int nextRight = nextLeft + button.getMeasuredWidth();
            if(nextRight > maxRight){ // if current button will exceed border on this row ...
                // ... move to next row
                nextLeft = getPaddingLeft();
                nextTop += maxRowHeight;

                // adjust for next row values
                nextRight = nextLeft + button.getMeasuredWidth();
                maxRowHeight = button.getMeasuredHeight();
            }

            int nextBottom = nextTop + button.getMeasuredHeight();
            viewRectMap.put(button, new Rect(nextLeft, nextTop, nextRight, nextBottom));

            // update nextLeft
            nextLeft = nextRight;
        }

        // height of RadioGroup is a natural by-product of placing all the children
        int idealHeight = nextTop + maxRowHeight + getPaddingBottom();
        switch(MeasureSpec.getMode(heightMeasureSpec)){
            case MeasureSpec.UNSPECIFIED:
                return idealHeight;
            case MeasureSpec.AT_MOST:
                return Math.min(idealHeight, parentHeight);
            case MeasureSpec.EXACTLY:
            default:
                return parentHeight;
        }
    }

    private int findVerticalWidth(int widthMeasureSpec, int heightMeasureSpec){
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int maxBottom = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom();

        // create MeasureSpecs to accommodate max space that RadioButtons can occupy
        int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
                parentWidth - (getPaddingLeft() + getPaddingRight()),
                MeasureSpec.getMode(widthMeasureSpec));
        int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxBottom - getPaddingTop(),
                MeasureSpec.getMode(heightMeasureSpec));

        int nextTop = getPaddingTop();
        int nextLeft = getPaddingLeft();
        int maxColWidth = 0;
        viewRectMap.clear();
        // measure and find placement for each RadioButton (results to be used in onLayout() stage)
        int count = getChildCount();
        for(int x=0; x < count; ++x){
            View button = getChildAt(x);
            measureChild(button, newWidthMeasureSpec, newHeightMeasureSpec);

            maxColWidth = Math.max(maxColWidth, button.getMeasuredWidth());

            // determine RadioButton placement
            int nextBottom = nextTop + button.getMeasuredHeight();
            if(nextBottom > maxBottom){ // if current button will exceed border for this column ...
                // ... move to next column
                nextTop = getPaddingTop();
                nextLeft += maxColWidth;

                // adjust for next row values
                nextBottom = nextTop + button.getMeasuredHeight();
                maxColWidth = button.getMeasuredWidth();
            }

            int nextRight = nextLeft + button.getMeasuredWidth();
            viewRectMap.put(button, new Rect(nextLeft, nextTop, nextRight, nextBottom));

            // update nextTop
            nextTop = nextBottom;
        }

        // width of RadioGroup is a natural by-product of placing all the children
        int idealWidth = nextLeft + maxColWidth + getPaddingRight();
        switch(MeasureSpec.getMode(widthMeasureSpec)){
            case MeasureSpec.UNSPECIFIED:
                return idealWidth;
            case MeasureSpec.AT_MOST:
                return Math.min(idealWidth, parentWidth);
            case MeasureSpec.EXACTLY:
            default:
                return parentWidth;
        }
    }
}