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