diff --git a/dlangui-msvc.visualdproj b/dlangui-msvc.visualdproj
index 05ebb8a0..91d25095 100644
--- a/dlangui-msvc.visualdproj
+++ b/dlangui-msvc.visualdproj
@@ -976,6 +976,7 @@
+
diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d
index 8f1a2a8d..8e2b39cb 100644
--- a/examples/example1/src/example1.d
+++ b/examples/example1/src/example1.d
@@ -417,6 +417,27 @@ extern (C) int UIAppMain(string[] args) {
};
tabs.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
+ // most of controls example
+ {
+ LinearLayout controls = new VerticalLayout("controls");
+ controls.padding = Rect(5,5,5,5);
+ HorizontalLayout line1 = new HorizontalLayout();
+ controls.addChild(line1);
+ GroupBox gb = new GroupBox("checkboxes", "Check boxes"d);
+ gb.addChild(new CheckBox("cb1", "Check Box 1"d));
+ gb.addChild(new CheckBox("cb2", "Check Box 2"d).checked(true));
+ gb.addChild(new CheckBox("cb3", "Check Box 3 (disabled)"d).enabled(false));
+ line1.addChild(gb);
+
+ GroupBox gb2 = new GroupBox("radiobuttons", "Radio buttons"d);
+ gb2.addChild(new RadioButton("rb1", "Radio button 1"d).checked(true));
+ gb2.addChild(new RadioButton("rb2", "Radio button 2"d));
+ gb2.addChild(new RadioButton("rb3", "Radio button (disabled)"d).enabled(false));
+ line1.addChild(gb2);
+
+ tabs.addTab(controls, "Controls"d);
+ }
+
LinearLayout layout = new LinearLayout("tab1");
layout.addChild((new TextWidget()).textColor(0x00802000).text("Text widget 0"));
diff --git a/src/dlangui/package.d b/src/dlangui/package.d
index 0c3c11ac..c675cd49 100644
--- a/src/dlangui/package.d
+++ b/src/dlangui/package.d
@@ -60,6 +60,7 @@ public {
import dlangui.widgets.widget;
import dlangui.widgets.controls;
import dlangui.widgets.layouts;
+ import dlangui.widgets.groupbox;
import dlangui.widgets.lists;
import dlangui.widgets.tabs;
import dlangui.widgets.menu;
diff --git a/src/dlangui/platforms/common/startup.d b/src/dlangui/platforms/common/startup.d
index 8e3b571e..e8881f1d 100644
--- a/src/dlangui/platforms/common/startup.d
+++ b/src/dlangui/platforms/common/startup.d
@@ -325,6 +325,7 @@ void registerStandardWidgets() {
import dlangui.widgets.combobox;
import dlangui.widgets.editors;
import dlangui.widgets.grid;
+ import dlangui.widgets.groupbox;
import dlangui.dialogs.filedlg;
import dlangui.widgets.menu;
mixin(registerWidgets!(FileNameEditLine, DirEditLine, //dlangui.dialogs.filedlg
@@ -332,6 +333,7 @@ void registerStandardWidgets() {
Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageCheckButton, ImageTextButton,
SwitchButton, RadioButton, CheckBox, ScrollBar, SliderWidget, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls
EditLine, EditBox, LogWidget,//dlangui.widgets.editors
+ GroupBox, // dlangui.widgets.groupbox
StringGridWidget, //dlangui.widgets.grid
VerticalLayout, HorizontalLayout, TableLayout, FrameLayout, // dlangui.widgets.layouts
ListWidget, StringListWidget,//dlangui.widgets.lists
diff --git a/src/dlangui/widgets/groupbox.d b/src/dlangui/widgets/groupbox.d
new file mode 100644
index 00000000..1fa0715a
--- /dev/null
+++ b/src/dlangui/widgets/groupbox.d
@@ -0,0 +1,207 @@
+// Written in the D programming language.
+
+/**
+This module contains Group Box widget implementation.
+
+Group box is linear layout with frame and caption for grouping controls.
+
+
+Synopsis:
+
+----
+import dlangui.widgets.groupbox;
+
+----
+
+Copyright: Vadim Lopatin, 2016
+License: Boost License 1.0
+Authors: Vadim Lopatin, coolreader.org@gmail.com
+*/
+module dlangui.widgets.groupbox;
+
+import dlangui.widgets.widget;
+import dlangui.widgets.layouts;
+
+class GroupBox : LinearLayout {
+ import dlangui.widgets.controls;
+
+ protected TextWidget _caption;
+
+ this() {
+ super("GROUP_BOX", Orientation.Vertical);
+ styleId = STYLE_GROUP_BOX;
+ _caption = new TextWidget("GROUP_BOX_CAPTION");
+ _caption.styleId = STYLE_GROUP_BOX_CAPTION;
+
+ }
+
+ this(string ID, UIString uitext, Orientation orientation = Orientation.Vertical) {
+ super(ID, orientation);
+ styleId = STYLE_GROUP_BOX;
+ _caption = new TextWidget("GROUP_BOX_CAPTION");
+ _caption.styleId = STYLE_GROUP_BOX_CAPTION;
+ _caption.parent = this;
+ text = uitext;
+ }
+
+ this(string ID, string textResourceId, Orientation orientation = Orientation.Vertical) {
+ super(ID, orientation);
+ styleId = STYLE_GROUP_BOX;
+ _caption = new TextWidget("GROUP_BOX_CAPTION");
+ _caption.styleId = STYLE_GROUP_BOX_CAPTION;
+ _caption.parent = this;
+ textResource = textResourceId;
+ }
+
+ this(string ID, dstring rawText, Orientation orientation = Orientation.Vertical) {
+ super(ID, orientation);
+ _caption = new TextWidget("GROUP_BOX_CAPTION");
+ _caption.styleId = STYLE_GROUP_BOX_CAPTION;
+ _caption.parent = this;
+ styleId = STYLE_GROUP_BOX;
+ text = rawText;
+ }
+
+ ~this() {
+ destroy(_caption);
+ }
+
+ /// get widget text
+ override @property dstring text() { return _caption.text; }
+ /// set text to show
+ override @property Widget text(dstring s) {
+ _caption.text = s;
+ requestLayout();
+ return this;
+ }
+ /// set text to show
+ override @property Widget text(UIString s) {
+ _caption.text = s;
+ requestLayout();
+ return this;
+ }
+ /// set text resource ID to show
+ @property Widget textResource(string s) {
+ _caption.textResource = s;
+ requestLayout();
+ return this;
+ }
+
+ int _topFrameHeight;
+ int _topFrameLeft;
+ int _topFrameRight;
+ int _captionHeight;
+ int _topHeight;
+ int _frameLeft;
+ int _frameRight;
+ int _frameBottom;
+ int _frameWidth;
+ int _frameHeight;
+ protected void calcFrame() {
+ Rect captPadding = _caption.padding;
+ Rect captMargins = _caption.margins;
+ int captFontHeight = _caption.font.height;
+ _captionHeight = captPadding.top + captPadding.bottom + captMargins.top + captMargins.bottom + captFontHeight;
+ _topFrameHeight = 0;
+ DrawableRef upLeftDrawable = style.customDrawable("group_box_frame_up_left");
+ DrawableRef upRightDrawable = style.customDrawable("group_box_frame_up_right");
+ if (!upLeftDrawable.isNull)
+ _topFrameHeight = upLeftDrawable.height;
+ if (!upRightDrawable.isNull && _topFrameHeight < upRightDrawable.height)
+ _topFrameHeight = upRightDrawable.height;
+ _topFrameLeft = 0;
+ if (!upLeftDrawable.isNull)
+ _topFrameLeft = upLeftDrawable.width;
+ _topFrameRight = 0;
+ if (!upRightDrawable.isNull)
+ _topFrameRight = upRightDrawable.width;
+ _frameLeft = _frameRight = _frameBottom = _frameWidth = 0;
+ DrawableRef bottomDrawable = style.customDrawable("group_box_frame_bottom");
+ if (!bottomDrawable.isNull) {
+ Rect dp = bottomDrawable.padding;
+ _frameLeft = dp.left;
+ _frameRight = dp.right;
+ _frameBottom = dp.bottom;
+ _frameWidth = bottomDrawable.width;
+ _frameHeight = bottomDrawable.height;
+ }
+ _topHeight = _captionHeight;
+ if (_topHeight < _topFrameHeight)
+ _topHeight = _topFrameHeight;
+ }
+
+ /// get padding (between background bounds and content of widget)
+ override @property Rect padding() const {
+ // get default padding
+ Rect p = super.padding();
+ // correct padding based on frame drawables and caption
+ (cast(GroupBox)this).calcFrame(); // hack
+ if (p.top < _topHeight)
+ p.top = _topHeight;
+ if (p.left < _frameLeft)
+ p.left = _frameLeft;
+ if (p.right < _frameRight)
+ p.right = _frameRight;
+ if (p.bottom < _frameBottom)
+ p.bottom = _frameBottom;
+ return p;
+ }
+
+ /// helper function for implement measure() when widget's content dimensions are known
+ override protected void measuredContent(int parentWidth, int parentHeight, int contentWidth, int contentHeight) {
+ _caption.measure(parentWidth, parentHeight);
+ calcFrame();
+ int w = _caption.measuredWidth;
+ if (contentWidth < w)
+ contentWidth = w;
+ super.measuredContent(parentWidth, parentHeight, contentWidth, contentHeight);
+ }
+
+ /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
+ override void layout(Rect rc) {
+ super.layout(rc);
+ Rect r = rc;
+ r.bottom = r.top + _topHeight;
+ r.left += _topFrameLeft;
+ r.right -= _topFrameRight;
+ _caption.measure(r.width, r.height);
+ if (r.width > _caption.measuredWidth)
+ r.right = r.left + _caption.measuredWidth;
+ _caption.layout(r);
+ }
+
+ /// set padding for widget - override one from style
+ override @property Widget padding(Rect rc) {
+ return super.padding(rc);
+ }
+
+ /// Draw widget at its position to buffer
+ override void onDraw(DrawBuf buf) {
+ if (visibility != Visibility.Visible)
+ return;
+ super.onDraw(buf);
+ Rect rc = _pos;
+ applyMargins(rc);
+
+ _caption.onDraw(buf);
+
+ int dh = 0;
+ if (_topFrameHeight < _captionHeight)
+ dh = (_captionHeight - _topFrameHeight) / 2;
+
+ DrawableRef upLeftDrawable = style.customDrawable("group_box_frame_up_left");
+ if (!upLeftDrawable.isNull) {
+ upLeftDrawable.drawTo(buf, Rect(rc.left, rc.top + dh, rc.left + _topFrameLeft, rc.top + _topHeight));
+ }
+ DrawableRef upRightDrawable = style.customDrawable("group_box_frame_up_right");
+ if (!upRightDrawable.isNull) {
+ int cw = _caption.width;
+ upRightDrawable.drawTo(buf, Rect(rc.left + _topFrameLeft + cw, rc.top + dh, rc.right, rc.top + _topHeight));
+ }
+
+ DrawableRef bottomDrawable = style.customDrawable("group_box_frame_bottom");
+ if (!bottomDrawable.isNull) {
+ bottomDrawable.drawTo(buf, Rect(rc.left, rc.top + _topHeight, rc.right, rc.bottom));
+ }
+ }
+}
diff --git a/src/dlangui/widgets/layouts.d b/src/dlangui/widgets/layouts.d
index a6c9dccb..532f0134 100644
--- a/src/dlangui/widgets/layouts.d
+++ b/src/dlangui/widgets/layouts.d
@@ -510,8 +510,8 @@ class LinearLayout : WidgetGroupDefaultDrawing {
this() {
this(null);
}
- /// create with ID parameter
- this(string ID) {
+ /// create with ID parameter and orientation
+ this(string ID, Orientation orientation = Orientation.Vertical) {
super(ID);
_layoutItems = new LayoutItems();
}
diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d
index 8e5d5589..53b3012e 100644
--- a/src/dlangui/widgets/styles.d
+++ b/src/dlangui/widgets/styles.d
@@ -115,6 +115,10 @@ immutable string STYLE_EDIT_BOX = "EDIT_BOX";
immutable string STYLE_STRING_GRID = "STRING_GRID";
/// standard style id for background similar to transparent button
immutable string STYLE_TRANSPARENT_BUTTON_BACKGROUND = "TRANSPARENT_BUTTON_BACKGROUND";
+/// standard style id for GroupBox
+immutable string STYLE_GROUP_BOX = "GROUP_BOX";
+/// standard style id for GroupBox caption
+immutable string STYLE_GROUP_BOX_CAPTION = "GROUP_BOX_CAPTION";
/// standard style id for tree item
immutable string STYLE_TREE_ITEM = "TREE_ITEM";
@@ -364,7 +368,7 @@ public:
}
/// get custom drawable attribute
- ref DrawableRef customDrawable(string id) {
+ ref DrawableRef customDrawable(string id) const {
if (id in _customDrawables)
return _customDrawables[id].drawable;
return parentStyle ? parentStyle.customDrawable(id) : currentTheme.customDrawable(id);
diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d
index 02e8370c..75ed2ceb 100644
--- a/src/dlangui/widgets/widget.d
+++ b/src/dlangui/widgets/widget.d
@@ -407,14 +407,14 @@ public:
@property Widget backgroundColor(uint color) {
ownStyle.backgroundColor = color;
invalidate();
- return this;
+ return this;
}
/// set background color for widget - from string like "#5599CC" or "white"
@property Widget backgroundColor(string colorString) {
uint color = decodeHexColor(colorString, COLOR_TRANSPARENT);
ownStyle.backgroundColor = color;
invalidate();
- return this;
+ return this;
}
/// background image id
diff --git a/views/res/group_box_frame_bottom.9.png b/views/res/group_box_frame_bottom.9.png
new file mode 100644
index 00000000..3d3a61cd
Binary files /dev/null and b/views/res/group_box_frame_bottom.9.png differ
diff --git a/views/res/group_box_frame_up_left.9.png b/views/res/group_box_frame_up_left.9.png
new file mode 100644
index 00000000..53844a0d
Binary files /dev/null and b/views/res/group_box_frame_up_left.9.png differ
diff --git a/views/res/group_box_frame_up_right.9.png b/views/res/group_box_frame_up_right.9.png
new file mode 100644
index 00000000..8d07389a
Binary files /dev/null and b/views/res/group_box_frame_up_right.9.png differ
diff --git a/views/res/theme_default.xml b/views/res/theme_default.xml
index 2d5cd4f3..e9787ab2 100644
--- a/views/res/theme_default.xml
+++ b/views/res/theme_default.xml
@@ -196,6 +196,7 @@
+
+
+
+
diff --git a/views/standard_resources.list b/views/standard_resources.list
index c15804eb..0e26052f 100644
--- a/views/standard_resources.list
+++ b/views/standard_resources.list
@@ -47,6 +47,9 @@ res/dock_window_caption_background_normal_down_dark.9.png
res/fileclose.png
res/fileopen.png
res/frame_blue.9.png
+res/group_box_frame_bottom.9.png
+res/group_box_frame_up_left.9.png
+res/group_box_frame_up_right.9.png
res/i18n/std_en.ini
res/i18n/std_ru.ini
res/list_item_background.xml