1 // Written in the D programming language.
2
3 /**
4 This module contains Group Box widget implementation.
5
6 Group box is linear layout with frame and caption for grouping controls.
7
8
9 Synopsis:
10
11 ----
12 import dlangui.widgets.groupbox;
13
14 ----
15
16 Copyright: Vadim Lopatin, 2016
17 License: Boost License 1.0
18 Authors: Vadim Lopatin, coolreader.org@gmail.com
19 */
20 module dlangui.widgets.groupbox;
21
22 import dlangui.widgets.widget;
23 import dlangui.widgets.layouts;
24
25 class GroupBox : LinearLayout {
26 import dlangui.widgets.controls;
27
28 protected TextWidget _caption;
29
30 this() {
31 this(null, ""d, Orientation.Vertical);
32 }
33
34 this(string ID, UIString uitext, Orientation orientation = Orientation.Vertical) {
35 super(ID, orientation);
36 styleId = STYLE_GROUP_BOX;
37 _caption = new TextWidget("GROUP_BOX_CAPTION");
38 _caption.styleId = STYLE_GROUP_BOX_CAPTION;
39 _caption.parent = this;
40 text = uitext;
41 }
42
43 this(string ID, string textResourceId, Orientation orientation = Orientation.Vertical) {
44 this(ID, UIString.fromId(textResourceId), orientation);
45 }
46
47 this(string ID, dstring rawText, Orientation orientation = Orientation.Vertical) {
48 this(ID, UIString.fromRaw(rawText), orientation);
49 }
50
51 ~this() {
52 destroy(_caption);
53 }
54
55 /// get widget text
56 override @property dstring text() { return _caption.text; }
57 /// set text to show
58 override @property Widget text(dstring s) {
59 _caption.text = s;
60 requestLayout();
61 return this;
62 }
63 /// set text to show
64 override @property Widget text(UIString s) {
65 _caption.text = s;
66 requestLayout();
67 return this;
68 }
69 /// set text resource ID to show
70 @property Widget textResource(string s) {
71 _caption.textResource = s;
72 requestLayout();
73 return this;
74 }
75
76 int _topFrameHeight;
77 int _topFrameLeft;
78 int _topFrameRight;
79 int _captionHeight;
80 int _topHeight;
81 int _frameLeft;
82 int _frameRight;
83 int _frameBottom;
84 int _frameWidth;
85 int _frameHeight;
86 protected void calcFrame() {
87 Rect captPadding = _caption.padding;
88 Rect captMargins = _caption.margins;
89 int captFontHeight = _caption.font.height;
90 _captionHeight = captPadding.top + captPadding.bottom + captMargins.top + captMargins.bottom + captFontHeight;
91 _topFrameHeight = 0;
92 DrawableRef upLeftDrawable = style.customDrawable("group_box_frame_up_left");
93 DrawableRef upRightDrawable = style.customDrawable("group_box_frame_up_right");
94 if (!upLeftDrawable.isNull)
95 _topFrameHeight = upLeftDrawable.height;
96 if (!upRightDrawable.isNull && _topFrameHeight < upRightDrawable.height)
97 _topFrameHeight = upRightDrawable.height;
98 _topFrameLeft = 0;
99 if (!upLeftDrawable.isNull)
100 _topFrameLeft = upLeftDrawable.width;
101 _topFrameRight = 0;
102 if (!upRightDrawable.isNull)
103 _topFrameRight = upRightDrawable.width;
104 _frameLeft = _frameRight = _frameBottom = _frameWidth = 0;
105 DrawableRef bottomDrawable = style.customDrawable("group_box_frame_bottom");
106 if (!bottomDrawable.isNull) {
107 Rect dp = bottomDrawable.padding;
108 _frameLeft = dp.left;
109 _frameRight = dp.right;
110 _frameBottom = dp.bottom;
111 _frameWidth = bottomDrawable.width;
112 _frameHeight = bottomDrawable.height;
113 }
114 _topHeight = _captionHeight;
115 if (_topHeight < _topFrameHeight)
116 _topHeight = _topFrameHeight;
117 }
118
119 /// handle theme change: e.g. reload some themed resources
120 override void onThemeChanged() {
121 super.onThemeChanged();
122 _caption.onThemeChanged();
123 }
124
125 /// get padding (between background bounds and content of widget)
126 override @property Rect padding() const {
127 // get default padding
128 Rect p = super.padding();
129 // correct padding based on frame drawables and caption
130 (cast(GroupBox)this).calcFrame(); // hack
131 if (p.top < _topHeight)
132 p.top = _topHeight;
133 if (p.left < _frameLeft)
134 p.left = _frameLeft;
135 if (p.right < _frameRight)
136 p.right = _frameRight;
137 if (p.bottom < _frameBottom)
138 p.bottom = _frameBottom;
139 return p;
140 }
141
142 /// helper function for implement measure() when widget's content dimensions are known
143 override protected void measuredContent(int parentWidth, int parentHeight, int contentWidth, int contentHeight) {
144 _caption.measure(parentWidth, parentHeight);
145 calcFrame();
146 int topPadding = _topFrameLeft + _topFrameRight;
147 int bottomPadding = _frameLeft + _frameRight;
148 int extraTop = topPadding - bottomPadding;
149 int w = _caption.measuredWidth + extraTop;
150 if (contentWidth < w)
151 contentWidth = w;
152 super.measuredContent(parentWidth, parentHeight, contentWidth, contentHeight);
153 }
154
155 /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
156 override void layout(Rect rc) {
157 super.layout(rc);
158 Rect r = rc;
159 r.top += margins.top;
160 r.bottom = r.top + _topHeight;
161 r.left += _topFrameLeft + margins.left;
162 r.right -= _topFrameRight;
163 _caption.measure(r.width, r.height);
164 if (r.width > _caption.measuredWidth)
165 r.right = r.left + _caption.measuredWidth;
166 _caption.layout(r);
167 }
168
169 /// set padding for widget - override one from style
170 override @property Widget padding(Rect rc) {
171 return super.padding(rc);
172 }
173
174 /// Draw widget at its position to buffer
175 override void onDraw(DrawBuf buf) {
176 if (visibility != Visibility.Visible)
177 return;
178 super.onDraw(buf);
179 Rect rc = _pos;
180 applyMargins(rc);
181
182 _caption.onDraw(buf);
183
184 int dh = 0;
185 if (_topFrameHeight < _captionHeight)
186 dh = (_captionHeight - _topFrameHeight) / 2;
187
188 DrawableRef upLeftDrawable = style.customDrawable("group_box_frame_up_left");
189 if (!upLeftDrawable.isNull) {
190 upLeftDrawable.drawTo(buf, Rect(rc.left, rc.top + dh, rc.left + _topFrameLeft, rc.top + _topHeight));
191 }
192 DrawableRef upRightDrawable = style.customDrawable("group_box_frame_up_right");
193 if (!upRightDrawable.isNull) {
194 int cw = _caption.width;
195 upRightDrawable.drawTo(buf, Rect(rc.left + _topFrameLeft + cw, rc.top + dh, rc.right, rc.top + _topHeight));
196 }
197
198 DrawableRef bottomDrawable = style.customDrawable("group_box_frame_bottom");
199 if (!bottomDrawable.isNull) {
200 bottomDrawable.drawTo(buf, Rect(rc.left, rc.top + _topHeight, rc.right, rc.bottom));
201 }
202 }
203 }