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 }