Merge branch 'master' of github.com:buggins/dlangui
|
@ -89,7 +89,6 @@
|
||||||
<resfile />
|
<resfile />
|
||||||
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
||||||
<useStdLibPath>1</useStdLibPath>
|
<useStdLibPath>1</useStdLibPath>
|
||||||
<cRuntime>2</cRuntime>
|
|
||||||
<additionalOptions />
|
<additionalOptions />
|
||||||
<preBuildCommand />
|
<preBuildCommand />
|
||||||
<postBuildCommand />
|
<postBuildCommand />
|
||||||
|
@ -184,7 +183,6 @@
|
||||||
<resfile />
|
<resfile />
|
||||||
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
||||||
<useStdLibPath>1</useStdLibPath>
|
<useStdLibPath>1</useStdLibPath>
|
||||||
<cRuntime>1</cRuntime>
|
|
||||||
<additionalOptions />
|
<additionalOptions />
|
||||||
<preBuildCommand />
|
<preBuildCommand />
|
||||||
<postBuildCommand />
|
<postBuildCommand />
|
||||||
|
@ -357,6 +355,7 @@
|
||||||
<File path="src\dlangui\dialogs\msgbox.d" />
|
<File path="src\dlangui\dialogs\msgbox.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder name="graphics">
|
<Folder name="graphics">
|
||||||
|
<File path="src\dlangui\graphics\colors.d" />
|
||||||
<File path="src\dlangui\graphics\drawbuf.d" />
|
<File path="src\dlangui\graphics\drawbuf.d" />
|
||||||
<File path="src\dlangui\graphics\fonts.d" />
|
<File path="src\dlangui\graphics\fonts.d" />
|
||||||
<File path="src\dlangui\graphics\ftfonts.d" />
|
<File path="src\dlangui\graphics\ftfonts.d" />
|
||||||
|
|
|
@ -89,7 +89,6 @@
|
||||||
<resfile />
|
<resfile />
|
||||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||||
<useStdLibPath>1</useStdLibPath>
|
<useStdLibPath>1</useStdLibPath>
|
||||||
<cRuntime>2</cRuntime>
|
|
||||||
<additionalOptions>-profile</additionalOptions>
|
<additionalOptions>-profile</additionalOptions>
|
||||||
<preBuildCommand />
|
<preBuildCommand />
|
||||||
<postBuildCommand />
|
<postBuildCommand />
|
||||||
|
@ -184,7 +183,6 @@
|
||||||
<resfile />
|
<resfile />
|
||||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||||
<useStdLibPath>1</useStdLibPath>
|
<useStdLibPath>1</useStdLibPath>
|
||||||
<cRuntime>1</cRuntime>
|
|
||||||
<additionalOptions />
|
<additionalOptions />
|
||||||
<preBuildCommand />
|
<preBuildCommand />
|
||||||
<postBuildCommand />
|
<postBuildCommand />
|
||||||
|
|
|
@ -424,15 +424,34 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LinearLayout layout3 = new LinearLayout("tab3");
|
LinearLayout layout3 = new VerticalLayout("tab3");
|
||||||
|
// 3 types of buttons: Button, ImageButton, ImageTextButton
|
||||||
layout3.addChild(new TextWidget(null, "Buttons in HorizontalLayout"d));
|
layout3.addChild(new TextWidget(null, "Buttons in HorizontalLayout"d));
|
||||||
WidgetGroup buttons1 = new HorizontalLayout();
|
WidgetGroup buttons1 = new HorizontalLayout();
|
||||||
buttons1.addChild(new Button("btn1", "Button 1"d));
|
buttons1.addChild(new TextWidget(null, "Button widgets: "d));
|
||||||
buttons1.addChild(new Button("btn2", "Button 2"d));
|
buttons1.addChild(new Button("btn1", "Button"d));
|
||||||
buttons1.addChild(new Button("btn3", "Button 3"d));
|
buttons1.addChild((new Button("btn2", "Disabled Button"d)).enabled(false));
|
||||||
buttons1.addChild(new ResizerWidget());
|
buttons1.addChild(new TextWidget(null, "ImageButton widgets: "d));
|
||||||
buttons1.addChild(new Button("btn4", "Button 4"d));
|
buttons1.addChild(new ImageButton("btn3", "text-plain"));
|
||||||
|
buttons1.addChild(new TextWidget(null, "disabled: "d));
|
||||||
|
buttons1.addChild((new ImageButton("btn4", "folder")).enabled(false));
|
||||||
|
buttons1.addChild(new TextWidget(null, "ImageTextButton widgets: "d));
|
||||||
|
buttons1.addChild(new ImageTextButton("btn5", "text-plain", "Enabled"d));
|
||||||
|
buttons1.addChild((new ImageTextButton("btn6", "folder", "Disabled"d)).enabled(false));
|
||||||
layout3.addChild(buttons1);
|
layout3.addChild(buttons1);
|
||||||
|
|
||||||
|
WidgetGroup buttons11 = new HorizontalLayout();
|
||||||
|
buttons11.addChild(new TextWidget(null, "Construct buttons by action (Button, ImageButton, ImageTextButton): "d));
|
||||||
|
Action FILE_OPEN_ACTION = new Action(ACTION_FILE_OPEN, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control);
|
||||||
|
buttons11.addChild(new Button(FILE_OPEN_ACTION));
|
||||||
|
buttons11.addChild(new ImageButton(FILE_OPEN_ACTION));
|
||||||
|
buttons11.addChild(new ImageTextButton(FILE_OPEN_ACTION));
|
||||||
|
buttons11.addChild(new TextWidget(null, "The same in disabled state: "d));
|
||||||
|
buttons11.addChild((new Button(FILE_OPEN_ACTION)).enabled(false));
|
||||||
|
buttons11.addChild((new ImageButton(FILE_OPEN_ACTION)).enabled(false));
|
||||||
|
buttons11.addChild((new ImageTextButton(FILE_OPEN_ACTION)).enabled(false));
|
||||||
|
layout3.addChild(buttons11);
|
||||||
|
|
||||||
layout3.addChild(new VSpacer());
|
layout3.addChild(new VSpacer());
|
||||||
layout3.addChild(new TextWidget(null, "CheckBoxes in HorizontalLayout"d));
|
layout3.addChild(new TextWidget(null, "CheckBoxes in HorizontalLayout"d));
|
||||||
WidgetGroup buttons2 = new HorizontalLayout();
|
WidgetGroup buttons2 = new HorizontalLayout();
|
||||||
|
@ -463,7 +482,7 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
layout3.addChild(new VSpacer());
|
layout3.addChild(new VSpacer());
|
||||||
layout3.addChild(new TextWidget(null, "In vertical layouts:"d));
|
layout3.addChild(new TextWidget(null, "In vertical layouts:"d));
|
||||||
HorizontalLayout hlayout2 = new HorizontalLayout();
|
HorizontalLayout hlayout2 = new HorizontalLayout();
|
||||||
hlayout2.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
hlayout2.layoutHeight(FILL_PARENT); //layoutWidth(FILL_PARENT).
|
||||||
|
|
||||||
buttons1 = new VerticalLayout();
|
buttons1 = new VerticalLayout();
|
||||||
buttons1.addChild(new TextWidget(null, "Buttons"d));
|
buttons1.addChild(new TextWidget(null, "Buttons"d));
|
||||||
|
@ -528,13 +547,19 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
table.addChild((new TextWidget(null, "Parameter 2 name bla bla"d)).alignment(Align.Right | Align.VCenter));
|
table.addChild((new TextWidget(null, "Parameter 2 name bla bla"d)).alignment(Align.Right | Align.VCenter));
|
||||||
table.addChild((new EditLine("edit2", "Some text for parameter 2"d)).layoutWidth(FILL_PARENT));
|
table.addChild((new EditLine("edit2", "Some text for parameter 2"d)).layoutWidth(FILL_PARENT));
|
||||||
// row 3
|
// row 3
|
||||||
table.addChild((new TextWidget(null, "Param 3"d)).alignment(Align.Right | Align.VCenter));
|
table.addChild((new TextWidget(null, "Param 3 is disabled"d)).alignment(Align.Right | Align.VCenter).enabled(false));
|
||||||
table.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT));
|
table.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT).enabled(false));
|
||||||
|
// normal readonly combo box
|
||||||
ComboBox combo1 = new ComboBox("combo1", ["item value 1"d, "item value 2"d, "item value 3"d, "item value 4"d, "item value 5"d, "item value 6"d]);
|
ComboBox combo1 = new ComboBox("combo1", ["item value 1"d, "item value 2"d, "item value 3"d, "item value 4"d, "item value 5"d, "item value 6"d]);
|
||||||
table.addChild((new TextWidget(null, "Combo box param"d)).alignment(Align.Right | Align.VCenter));
|
table.addChild((new TextWidget(null, "Combo box param"d)).alignment(Align.Right | Align.VCenter));
|
||||||
combo1.selectedItemIndex(3);
|
combo1.selectedItemIndex = 3;
|
||||||
table.addChild(combo1).layoutWidth(FILL_PARENT);
|
table.addChild(combo1).layoutWidth(FILL_PARENT);
|
||||||
|
// disabled readonly combo box
|
||||||
|
ComboBox combo2 = new ComboBox("combo2", ["item value 1"d, "item value 2"d, "item value 3"d]);
|
||||||
|
table.addChild((new TextWidget(null, "Disabled combo box"d)).alignment(Align.Right | Align.VCenter));
|
||||||
|
combo2.enabled = false;
|
||||||
|
combo2.selectedItemIndex = 0;
|
||||||
|
table.addChild(combo2).layoutWidth(FILL_PARENT);
|
||||||
|
|
||||||
table.margins(Rect(10,10,10,10)).layoutWidth(FILL_PARENT);
|
table.margins(Rect(10,10,10,10)).layoutWidth(FILL_PARENT);
|
||||||
tabs.addTab(table, "TAB_TABLE_LAYOUT"c);
|
tabs.addTab(table, "TAB_TABLE_LAYOUT"c);
|
||||||
|
@ -639,11 +664,11 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
table2.addChild((new TextWidget(null, "Param 5 - edit text here - blah blah blah"d)).alignment(Align.Right | Align.VCenter));
|
table2.addChild((new TextWidget(null, "Param 5 - edit text here - blah blah blah"d)).alignment(Align.Right | Align.VCenter));
|
||||||
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
||||||
// row 6
|
// row 6
|
||||||
table2.addChild((new TextWidget(null, "Param 6 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter));
|
table2.addChild((new TextWidget(null, "Param 6 - just to fill content widget (DISABLED)"d)).alignment(Align.Right | Align.VCenter).enabled(false));
|
||||||
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT).enabled(false));
|
||||||
// row 7
|
// row 7
|
||||||
table2.addChild((new TextWidget(null, "Param 7 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter));
|
table2.addChild((new TextWidget(null, "Param 7 - just to fill content widget (DISABLED)"d)).alignment(Align.Right | Align.VCenter).enabled(false));
|
||||||
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT).enabled(false));
|
||||||
// row 8
|
// row 8
|
||||||
table2.addChild((new TextWidget(null, "Param 8 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter));
|
table2.addChild((new TextWidget(null, "Param 8 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter));
|
||||||
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/btn_pressed" />
|
||||||
|
<item android:state_focused="true" android:state_default="true" android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_default" />
|
||||||
|
<item android:state_focused="true" android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_normal" />
|
||||||
|
<item android:state_enabled="true" android:state_default="true"
|
||||||
|
android:drawable="@drawable/btn_default" />
|
||||||
|
<item android:state_enabled="true" android:state_hovered="true"
|
||||||
|
android:drawable="@drawable/btn_hover" />
|
||||||
|
<item android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_normal" />
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/btn_disabled" />
|
||||||
|
</selector>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item
|
||||||
|
android:drawable="@null"
|
||||||
|
android:state_enabled="false"/>
|
||||||
|
<item
|
||||||
|
android:drawable="@null"
|
||||||
|
android:state_focused="true" />
|
||||||
|
<item
|
||||||
|
android:drawable="btn_pressed"
|
||||||
|
android:state_pressed="true" />
|
||||||
|
<item
|
||||||
|
android:drawable="btn_hover"
|
||||||
|
android:state_hovered="true" android:state_enabled="true" />
|
||||||
|
<item
|
||||||
|
android:drawable="@null" />
|
||||||
|
</selector>
|
|
@ -1,65 +1,45 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<!-- Enabled states -->
|
<!-- Enabled states -->
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_window_focused="false"
|
|
||||||
android:state_enabled="true"
|
|
||||||
android:drawable="@drawable/btn_check_on_holo_light" />
|
|
||||||
<item android:state_checked="false" android:state_window_focused="false"
|
|
||||||
android:state_enabled="true"
|
|
||||||
android:drawable="@drawable/btn_check_off_holo_light" />
|
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_pressed="true"
|
<item android:state_checked="true" android:state_pressed="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_on_pressed_holo_light" />
|
android:drawable="@drawable/btn_check_on_pressed" />
|
||||||
<item android:state_checked="false" android:state_pressed="true"
|
<item android:state_checked="false" android:state_pressed="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_off_pressed_holo_light" />
|
android:drawable="@drawable/btn_check_off_pressed" />
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_focused="true"
|
<item android:state_checked="true" android:state_focused="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_on_focused_holo_light" />
|
android:drawable="@drawable/btn_check_on_focused" />
|
||||||
<item android:state_checked="false" android:state_focused="true"
|
<item android:state_checked="false" android:state_focused="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_off_focused_holo_light" />
|
android:drawable="@drawable/btn_check_off_focused" />
|
||||||
|
|
||||||
|
<item android:state_checked="true" android:state_hovered="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_check_on_focused" />
|
||||||
|
<item android:state_checked="false" android:state_hovered="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_check_off_focused" />
|
||||||
|
|
||||||
<item android:state_checked="false"
|
<item android:state_checked="false"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_off_holo_light" />
|
android:drawable="@drawable/btn_check_off" />
|
||||||
<item android:state_checked="true"
|
<item android:state_checked="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_check_on_holo_light" />
|
android:drawable="@drawable/btn_check_on" />
|
||||||
|
|
||||||
|
|
||||||
<!-- Disabled states -->
|
<!-- Disabled states -->
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_window_focused="false"
|
<item android:state_checked="true"
|
||||||
android:drawable="@drawable/btn_check_on_disabled_holo_light" />
|
android:drawable="@drawable/btn_check_on_disabled" />
|
||||||
<item android:state_checked="false" android:state_window_focused="false"
|
<item android:state_checked="false"
|
||||||
android:drawable="@drawable/btn_check_off_disabled_holo_light" />
|
android:drawable="@drawable/btn_check_off_disabled" />
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_focused="true"
|
<item android:state_checked="false" android:drawable="@drawable/btn_check_off" />
|
||||||
android:drawable="@drawable/btn_check_on_disabled_focused_holo_light" />
|
<item android:state_checked="true" android:drawable="@drawable/btn_check_on" />
|
||||||
<item android:state_checked="false" android:state_focused="true"
|
|
||||||
android:drawable="@drawable/btn_check_off_disabled_focused_holo_light" />
|
|
||||||
|
|
||||||
<item android:state_checked="false" android:drawable="@drawable/btn_check_off_disabled_holo_light" />
|
|
||||||
<item android:state_checked="true" android:drawable="@drawable/btn_check_on_disabled_holo_light" />
|
|
||||||
|
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -1,59 +1,34 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_checked="true" android:state_window_focused="false"
|
|
||||||
android:state_enabled="true"
|
|
||||||
android:drawable="@drawable/btn_radio_on_holo_light" />
|
|
||||||
<item android:state_checked="false" android:state_window_focused="false"
|
|
||||||
android:state_enabled="true"
|
|
||||||
android:drawable="@drawable/btn_radio_off_holo_light" />
|
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_pressed="true"
|
<item android:state_checked="true" android:state_pressed="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_on_pressed_holo_light" />
|
android:drawable="@drawable/btn_radio_on_pressed" />
|
||||||
<item android:state_checked="false" android:state_pressed="true"
|
<item android:state_checked="false" android:state_pressed="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_off_pressed_holo_light" />
|
android:drawable="@drawable/btn_radio_off_pressed" />
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_focused="true"
|
<item android:state_checked="true" android:state_focused="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_on_focused_holo_light" />
|
android:drawable="@drawable/btn_radio_on_focused" />
|
||||||
<item android:state_checked="false" android:state_focused="true"
|
<item android:state_checked="false" android:state_focused="true"
|
||||||
android:state_enabled="true"
|
android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_off_focused_holo_light" />
|
android:drawable="@drawable/btn_radio_off_focused" />
|
||||||
|
|
||||||
|
<item android:state_checked="true" android:state_hovered="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_radio_on_focused" />
|
||||||
|
<item android:state_checked="false" android:state_hovered="true"
|
||||||
|
android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_radio_off_focused" />
|
||||||
|
|
||||||
<item android:state_checked="false" android:state_enabled="true"
|
<item android:state_checked="false" android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_off_holo_light" />
|
android:drawable="@drawable/btn_radio_off" />
|
||||||
<item android:state_checked="true" android:state_enabled="true"
|
<item android:state_checked="true" android:state_enabled="true"
|
||||||
android:drawable="@drawable/btn_radio_on_holo_light" />
|
android:drawable="@drawable/btn_radio_on" />
|
||||||
|
|
||||||
<!-- Disabled states -->
|
<!-- Disabled states -->
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_window_focused="false"
|
<item android:state_checked="false" android:drawable="@drawable/btn_radio_off_disabled" />
|
||||||
android:drawable="@drawable/btn_radio_on_disabled_holo_light" />
|
<item android:state_checked="true" android:drawable="@drawable/btn_radio_on_disabled" />
|
||||||
<item android:state_checked="false" android:state_window_focused="false"
|
|
||||||
android:drawable="@drawable/btn_radio_off_disabled_holo_light" />
|
|
||||||
|
|
||||||
<item android:state_checked="true" android:state_focused="true"
|
|
||||||
android:drawable="@drawable/btn_radio_on_disabled_focused_holo_light" />
|
|
||||||
<item android:state_checked="false" android:state_focused="true"
|
|
||||||
android:drawable="@drawable/btn_radio_off_disabled_focused_holo_light" />
|
|
||||||
|
|
||||||
<item android:state_checked="false" android:drawable="@drawable/btn_radio_off_disabled_holo_light" />
|
|
||||||
<item android:state_checked="true" android:drawable="@drawable/btn_radio_on_disabled_holo_light" />
|
|
||||||
|
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/btn_pressed" />
|
||||||
|
<item android:state_focused="true" android:state_default="true" android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_default" />
|
||||||
|
<item android:state_focused="true" android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_default" />
|
||||||
|
<item android:state_enabled="true" android:state_default="true"
|
||||||
|
android:drawable="@drawable/btn_default" />
|
||||||
|
<item android:state_enabled="true" android:state_hovered="true"
|
||||||
|
android:drawable="@drawable/btn_hover" />
|
||||||
|
<item android:state_enabled="true"
|
||||||
|
android:drawable="@drawable/btn_normal" />
|
||||||
|
<item
|
||||||
|
android:drawable="@drawable/btn_disabled" />
|
||||||
|
</selector>
|
||||||
|
|
|
@ -1,26 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
/* //device/apps/common/assets/res/any/drawable/editbox_background.xml
|
|
||||||
**
|
|
||||||
** Copyright 2006, The Android Open Source Project
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/editbox_background_disabled_focus_yellow" />
|
<item android:state_focused="true" android:state_enabled="false" android:drawable="editbox_background_disabled_focus" />
|
||||||
<item android:state_focused="true" android:drawable="@drawable/editbox_background_focus_yellow" />
|
<item android:state_focused="true" android:drawable="editbox_background_focus" />
|
||||||
<item android:state_enabled="false" android:drawable="@drawable/editbox_background_disabled" />
|
<item android:state_enabled="false" android:drawable="editbox_background_disabled" />
|
||||||
<item android:drawable="@drawable/editbox_background_normal" />
|
<item android:drawable="editbox_background_normal" />
|
||||||
</selector>
|
</selector>
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 360 B |
After Width: | Height: | Size: 241 B |
Before Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 329 B |
After Width: | Height: | Size: 353 B |
Before Width: | Height: | Size: 425 B |
Before Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 491 B |
After Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 514 B |
After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 632 B |
Before Width: | Height: | Size: 508 B |
After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 528 B |
Before Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 532 B |
After Width: | Height: | Size: 354 B |
After Width: | Height: | Size: 461 B |
After Width: | Height: | Size: 412 B |
After Width: | Height: | Size: 537 B |
After Width: | Height: | Size: 584 B |
After Width: | Height: | Size: 583 B |
Before Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 479 B |
After Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 584 B |
Before Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 625 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 736 B |
After Width: | Height: | Size: 644 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 578 B |
After Width: | Height: | Size: 632 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 216 B |
|
@ -1,25 +1,68 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<theme id="theme_default" fontSize="15" >
|
<theme id="theme_default" fontSize="15" >
|
||||||
<style id="BUTTON"
|
<style id="BUTTON"
|
||||||
backgroundImageId="btn_default_small"
|
backgroundImageId="btn_background"
|
||||||
align="Center"
|
align="Center"
|
||||||
margins="5,5,5,5"
|
margins="5,5,5,5"
|
||||||
/>
|
focusRectColors="#000"
|
||||||
|
textFlags="UnderlineHotKeys"
|
||||||
|
>
|
||||||
|
<state state_enabled="true" state_hovered="true" textColor="#006080"/>
|
||||||
|
<state state_enabled="false" textColor="#80000000"/>
|
||||||
|
</style>
|
||||||
<style id="BUTTON_TRANSPARENT"
|
<style id="BUTTON_TRANSPARENT"
|
||||||
backgroundImageId="btn_default_small_transparent"
|
backgroundImageId="btn_background_transparent"
|
||||||
align="Center"
|
align="Center"
|
||||||
/>
|
/>
|
||||||
<style id="BUTTON_LABEL"
|
<style id="BUTTON_LABEL"
|
||||||
layoutWidth="FILL_PARENT"
|
layoutWidth="FILL_PARENT"
|
||||||
|
margins="2,2,2,2"
|
||||||
align="Left|VCenter"
|
align="Left|VCenter"
|
||||||
/>
|
textFlags="UnderlineHotKeys"
|
||||||
<style id="BUTTON_ICON"
|
>
|
||||||
|
<state state_enabled="false" textColor="#80000000"/>
|
||||||
|
<state state_enabled="true" state_hovered="true" textColor="#006080"/>
|
||||||
|
</style>
|
||||||
|
<style id="BUTTON_IMAGE"
|
||||||
|
margins="2,2,2,2"
|
||||||
align="Center"
|
align="Center"
|
||||||
/>
|
/>
|
||||||
|
<style id="CHECKBOX"
|
||||||
|
backgroundImageId="@null"
|
||||||
|
margins="2,2,2,2"
|
||||||
|
padding="2,2,2,2"
|
||||||
|
focusRectColors="@null"
|
||||||
|
/>
|
||||||
|
<style id="CHECKBOX_IMAGE" parent="BUTTON_IMAGE"
|
||||||
|
align="Center"
|
||||||
|
margins="2,2,2,2"
|
||||||
|
/>
|
||||||
|
<style id="CHECKBOX_LABEL" parent="BUTTON_LABEL"
|
||||||
|
align="Left|VCenter"
|
||||||
|
focusRectColors="#000"
|
||||||
|
>
|
||||||
|
<state state_enabled="true" state_hovered="true" textColor="#006080"/>
|
||||||
|
</style>
|
||||||
|
<style id="RADIOBUTTON" parent="CHECKBOX"
|
||||||
|
margins="2,2,2,2"
|
||||||
|
padding="2,2,2,2"
|
||||||
|
/>
|
||||||
|
<style id="RADIOBUTTON_IMAGE" parent="CHECKBOX_IMAGE"
|
||||||
|
align="Center"
|
||||||
|
margins="2,2,2,2"
|
||||||
|
/>
|
||||||
|
<style id="RADIOBUTTON_LABEL" parent="CHECKBOX_LABEL"
|
||||||
|
align="Left|VCenter"
|
||||||
|
>
|
||||||
|
<state state_enabled="true" state_hovered="true" textColor="#006080"/>
|
||||||
|
</style>
|
||||||
<style id="TEXT"
|
<style id="TEXT"
|
||||||
margins="2,2,2,2"
|
margins="2,2,2,2"
|
||||||
padding="1,1,1,1"
|
padding="1,1,1,1"
|
||||||
/>
|
align="Left|VCenter"
|
||||||
|
>
|
||||||
|
<state state_enabled="false" textColor="#A0000000"/>
|
||||||
|
</style>
|
||||||
<style id="HSPACER"
|
<style id="HSPACER"
|
||||||
layoutWidth="FILL_PARENT"
|
layoutWidth="FILL_PARENT"
|
||||||
layoutWeight="100"
|
layoutWeight="100"
|
||||||
|
@ -31,9 +74,13 @@
|
||||||
minHeight="5"
|
minHeight="5"
|
||||||
/>
|
/>
|
||||||
<style id="BUTTON_NOMARGINS"
|
<style id="BUTTON_NOMARGINS"
|
||||||
backgroundImageId="btn_default_small"
|
backgroundImageId="btn_background"
|
||||||
align="Center"
|
align="Center"
|
||||||
/>
|
/>
|
||||||
|
<color id="sample_color_rgb" value="#8CF"/>
|
||||||
|
<color id="sample_color_argb" value="#48CF"/>
|
||||||
|
<color id="sample_color_rrggbb" value="#80C0F0"/>
|
||||||
|
<color id="sample_color_aarrggbb" value="#4080C0F0"/>
|
||||||
<drawable id="scrollbar_button_up" value="scrollbar_btn_up"/>
|
<drawable id="scrollbar_button_up" value="scrollbar_btn_up"/>
|
||||||
<drawable id="scrollbar_button_down" value="scrollbar_btn_down"/>
|
<drawable id="scrollbar_button_down" value="scrollbar_btn_down"/>
|
||||||
<drawable id="scrollbar_button_left" value="scrollbar_btn_left"/>
|
<drawable id="scrollbar_button_left" value="scrollbar_btn_left"/>
|
||||||
|
@ -134,43 +181,39 @@
|
||||||
<style id="LIST_ITEM"
|
<style id="LIST_ITEM"
|
||||||
backgroundImageId="list_item_background"
|
backgroundImageId="list_item_background"
|
||||||
/>
|
/>
|
||||||
<style id="EDIT_LINE"
|
|
||||||
backgroundImageId="editbox_background"
|
|
||||||
padding="5,6,5,6"
|
|
||||||
margins="2,2,2,2"
|
|
||||||
minWidth="40"
|
|
||||||
fontFace="Arial"
|
|
||||||
fontFamily="SansSerif"
|
|
||||||
fontSize="16"
|
|
||||||
/>
|
|
||||||
<style id="COMBO_BOX"
|
<style id="COMBO_BOX"
|
||||||
backgroundImageId="editbox_background"
|
backgroundImageId="combobox_background"
|
||||||
padding="2,2,2,2"
|
padding="2,2,2,2"
|
||||||
margins="2,2,2,2"
|
margins="2,2,2,2"
|
||||||
minWidth="40"
|
minWidth="40"
|
||||||
fontFace="Arial"
|
|
||||||
fontFamily="SansSerif"
|
|
||||||
fontSize="16"
|
|
||||||
/>
|
/>
|
||||||
<style id="COMBO_BOX_BODY"
|
<style id="COMBO_BOX_BODY"
|
||||||
padding="2,2,2,2"
|
padding="2,2,2,2"
|
||||||
minWidth="40"
|
minWidth="40"
|
||||||
fontFace="Arial"
|
|
||||||
fontFamily="SansSerif"
|
|
||||||
fontSize="16"
|
|
||||||
align="Left|VCenter"
|
align="Left|VCenter"
|
||||||
|
focusRectColors="#000"
|
||||||
|
/>
|
||||||
|
<style id="COMBO_BOX_BUTTON"
|
||||||
|
padding="2,2,2,2"
|
||||||
|
backgroundImageId="btn_background_transparent"
|
||||||
|
align="Center"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style id="EDIT_LINE"
|
||||||
|
backgroundImageId="editbox_background"
|
||||||
|
padding="4,4,4,4"
|
||||||
|
margins="2,2,2,2"
|
||||||
|
minWidth="40"
|
||||||
/>
|
/>
|
||||||
<style id="EDIT_BOX"
|
<style id="EDIT_BOX"
|
||||||
backgroundImageId="editbox_background"
|
backgroundImageId="editbox_background"
|
||||||
padding="5,6,5,6"
|
padding="2,2,2,2"
|
||||||
margins="2,2,2,2"
|
margins="2,2,2,2"
|
||||||
minWidth="100"
|
minWidth="100"
|
||||||
minHeight="60"
|
minHeight="60"
|
||||||
layoutWidth="FILL_PARENT"
|
layoutWidth="FILL_PARENT"
|
||||||
layoutHeight="FILL_PARENT"
|
layoutHeight="FILL_PARENT"
|
||||||
fontFace="Courier New"
|
|
||||||
fontFamily="MonoSpace"
|
|
||||||
fontSize="16"
|
|
||||||
/>
|
/>
|
||||||
<style id="TREE_ITEM"
|
<style id="TREE_ITEM"
|
||||||
padding="2,2,2,2"
|
padding="2,2,2,2"
|
||||||
|
|
|
@ -64,6 +64,7 @@ public import dlangui.widgets.grid;
|
||||||
public import dlangui.widgets.tree;
|
public import dlangui.widgets.tree;
|
||||||
public import dlangui.widgets.combobox;
|
public import dlangui.widgets.combobox;
|
||||||
public import dlangui.widgets.popup;
|
public import dlangui.widgets.popup;
|
||||||
|
public import dlangui.graphics.colors;
|
||||||
public import dlangui.graphics.fonts;
|
public import dlangui.graphics.fonts;
|
||||||
public import dlangui.graphics.drawbuf;
|
public import dlangui.graphics.drawbuf;
|
||||||
public import dlangui.platforms.common.platform;
|
public import dlangui.platforms.common.platform;
|
||||||
|
|
|
@ -221,3 +221,82 @@ struct Collection(T, bool ownItems = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** object list holder, owning its objects - on destroy of holder, all own objects will be destroyed */
|
||||||
|
struct ObjectList(T) {
|
||||||
|
protected T[] _list;
|
||||||
|
protected int _count;
|
||||||
|
/** returns count of items */
|
||||||
|
@property int count() const { return _count; }
|
||||||
|
/** get item by index */
|
||||||
|
T get(int index) {
|
||||||
|
assert(index >= 0 && index < _count, "child index out of range");
|
||||||
|
return _list[index];
|
||||||
|
}
|
||||||
|
/// get item by index
|
||||||
|
T opIndex(int index) {
|
||||||
|
return get(index);
|
||||||
|
}
|
||||||
|
/** add item to list */
|
||||||
|
T add(T item) {
|
||||||
|
if (_list.length <= _count) // resize
|
||||||
|
_list.length = _list.length < 4 ? 4 : _list.length * 2;
|
||||||
|
_list[_count++] = item;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
/** add item to list */
|
||||||
|
T insert(T item, int index = -1) {
|
||||||
|
if (index > _count || index < 0)
|
||||||
|
index = _count;
|
||||||
|
if (_list.length <= _count) // resize
|
||||||
|
_list.length = _list.length < 4 ? 4 : _list.length * 2;
|
||||||
|
for (int i = _count; i > index; i--)
|
||||||
|
_list[i] = _list[i - 1];
|
||||||
|
_list[index] = item;
|
||||||
|
_count++;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
/** find child index for item, return -1 if not found */
|
||||||
|
int indexOf(T item) {
|
||||||
|
for (int i = 0; i < _count; i++)
|
||||||
|
if (_list[i] == item)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/** find child index for item by id, return -1 if not found */
|
||||||
|
static if (__traits(hasMember, T, "compareId")) {
|
||||||
|
int indexOf(string id) {
|
||||||
|
for (int i = 0; i < _count; i++)
|
||||||
|
if (_list[i].compareId(id))
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** remove item from list, return removed item */
|
||||||
|
T remove(int index) {
|
||||||
|
assert(index >= 0 && index < _count, "child index out of range");
|
||||||
|
T item = _list[index];
|
||||||
|
for (int i = index; i < _count - 1; i++)
|
||||||
|
_list[i] = _list[i + 1];
|
||||||
|
_count--;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
/** Replace item with another value, destroy old value. */
|
||||||
|
void replace(T item, int index) {
|
||||||
|
T old = _list[index];
|
||||||
|
_list[index] = item;
|
||||||
|
destroy(old);
|
||||||
|
}
|
||||||
|
/** remove and destroy all items */
|
||||||
|
void clear() {
|
||||||
|
for (int i = 0; i < _count; i++) {
|
||||||
|
destroy(_list[i]);
|
||||||
|
_list[i] = null;
|
||||||
|
}
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
~this() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Dialog : VerticalLayout {
|
||||||
Signal!DialogResultHandler onDialogResult;
|
Signal!DialogResultHandler onDialogResult;
|
||||||
|
|
||||||
this(UIString caption, Window parentWindow = null, uint flags = DialogFlag.Modal) {
|
this(UIString caption, Window parentWindow = null, uint flags = DialogFlag.Modal) {
|
||||||
super("dlg");
|
super("dialog-main-widget");
|
||||||
_caption = caption;
|
_caption = caption;
|
||||||
_parentWindow = parentWindow;
|
_parentWindow = parentWindow;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
|
@ -155,8 +155,11 @@ class Dialog : VerticalLayout {
|
||||||
uint wflags = 0;
|
uint wflags = 0;
|
||||||
if (_flags & DialogFlag.Modal)
|
if (_flags & DialogFlag.Modal)
|
||||||
wflags |= WindowFlag.Modal;
|
wflags |= WindowFlag.Modal;
|
||||||
if (_flags & DialogFlag.Resizable)
|
if (_flags & DialogFlag.Resizable) {
|
||||||
wflags |= WindowFlag.Resizable;
|
wflags |= WindowFlag.Resizable;
|
||||||
|
layoutWidth = FILL_PARENT;
|
||||||
|
layoutHeight = FILL_PARENT;
|
||||||
|
}
|
||||||
_window = Platform.instance.createWindow(_caption, _parentWindow, wflags);
|
_window = Platform.instance.createWindow(_caption, _parentWindow, wflags);
|
||||||
if (_window && _icon)
|
if (_window && _icon)
|
||||||
_window.windowIcon = drawableCache.getImage(_icon);
|
_window.windowIcon = drawableCache.getImage(_icon);
|
||||||
|
|
|
@ -133,13 +133,6 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
|
||||||
override void layout(Rect rc) {
|
|
||||||
super.layout(rc);
|
|
||||||
_fileList.autoFitColumnWidths();
|
|
||||||
_fileList.fillColumnWidth(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool upLevel() {
|
protected bool upLevel() {
|
||||||
return openDirectory(parentDir(_path), _path);
|
return openDirectory(parentDir(_path), _path);
|
||||||
}
|
}
|
||||||
|
@ -234,12 +227,12 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
|
|
||||||
protected ListWidget createRootsList() {
|
protected ListWidget createRootsList() {
|
||||||
ListWidget res = new ListWidget("ROOTS_LIST");
|
ListWidget res = new ListWidget("ROOTS_LIST");
|
||||||
res.styleId = "EDIT_BOX";
|
res.styleId = STYLE_EDIT_BOX;
|
||||||
WidgetListAdapter adapter = new WidgetListAdapter();
|
WidgetListAdapter adapter = new WidgetListAdapter();
|
||||||
foreach(ref RootEntry root; _roots) {
|
foreach(ref RootEntry root; _roots) {
|
||||||
ImageTextButton btn = new ImageTextButton(null, root.icon, root.label);
|
ImageTextButton btn = new ImageTextButton(null, root.icon, root.label);
|
||||||
btn.orientation = Orientation.Vertical;
|
btn.orientation = Orientation.Vertical;
|
||||||
btn.styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
btn.styleId = STYLE_TRANSPARENT_BUTTON_BACKGROUND;
|
||||||
btn.focusable = false;
|
btn.focusable = false;
|
||||||
adapter.widgets.add(btn);
|
adapter.widgets.add(btn);
|
||||||
}
|
}
|
||||||
|
@ -310,11 +303,11 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
layoutWidth(FILL_PARENT);
|
layoutWidth(FILL_PARENT);
|
||||||
layoutWidth(FILL_PARENT);
|
layoutWidth(FILL_PARENT);
|
||||||
minWidth = 600;
|
minWidth = 600;
|
||||||
minHeight = 400;
|
//minHeight = 400;
|
||||||
|
|
||||||
LinearLayout content = new HorizontalLayout("dlgcontent");
|
LinearLayout content = new HorizontalLayout("dlgcontent");
|
||||||
|
|
||||||
content.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT).minWidth(400).minHeight(300);
|
content.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); //.minWidth(400).minHeight(300);
|
||||||
|
|
||||||
leftPanel = new VerticalLayout("places");
|
leftPanel = new VerticalLayout("places");
|
||||||
leftPanel.addChild(createRootsList());
|
leftPanel.addChild(createRootsList());
|
||||||
|
@ -387,6 +380,28 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||||
|
override void layout(Rect rc) {
|
||||||
|
super.layout(rc);
|
||||||
|
_fileList.autoFitColumnWidths();
|
||||||
|
_fileList.fillColumnWidth(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||||
|
//override void measure(int parentWidth, int parentHeight) {
|
||||||
|
// super.measure(parentWidth, parentHeight);
|
||||||
|
// for(int i = 0; i < childCount; i++) {
|
||||||
|
// Widget w = child(i);
|
||||||
|
// Log.d("id=", w.id, " measuredHeight=", w.measuredHeight );
|
||||||
|
// for (int j = 0; j < w.childCount; j++) {
|
||||||
|
// Widget w2 = w.child(j);
|
||||||
|
// Log.d(" id=", w2.id, " measuredHeight=", w.measuredHeight );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Log.d("this id=", id, " measuredHeight=", measuredHeight);
|
||||||
|
//}
|
||||||
|
|
||||||
override void onShow() {
|
override void onShow() {
|
||||||
_fileList.setFocus();
|
_fileList.setFocus();
|
||||||
}
|
}
|
||||||
|
@ -403,17 +418,17 @@ class FilePathPanelItem : HorizontalLayout {
|
||||||
Listener!OnPathSelectionHandler onPathSelectionListener;
|
Listener!OnPathSelectionHandler onPathSelectionListener;
|
||||||
this(string path) {
|
this(string path) {
|
||||||
super(null);
|
super(null);
|
||||||
styleId = "LIST_ITEM";
|
styleId = STYLE_LIST_ITEM;
|
||||||
_path = path;
|
_path = path;
|
||||||
string fname = isRoot(path) ? path : baseName(path);
|
string fname = isRoot(path) ? path : baseName(path);
|
||||||
_text = new TextWidget(null, toUTF32(fname));
|
_text = new TextWidget(null, toUTF32(fname));
|
||||||
_text.styleId = "BUTTON_TRANSPARENT";
|
_text.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||||
_text.clickable = true;
|
_text.clickable = true;
|
||||||
_text.onClickListener = &onTextClick;
|
_text.onClickListener = &onTextClick;
|
||||||
//_text.backgroundColor = 0xC0FFFF;
|
//_text.backgroundColor = 0xC0FFFF;
|
||||||
_text.state = State.Parent;
|
_text.state = State.Parent;
|
||||||
_button = new ImageButton(null, "scrollbar_btn_right");
|
_button = new ImageButton(null, "scrollbar_btn_right");
|
||||||
_button.styleId = "BUTTON_TRANSPARENT";
|
_button.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||||
_button.focusable = false;
|
_button.focusable = false;
|
||||||
_button.onClickListener = &onButtonClick;
|
_button.onClickListener = &onButtonClick;
|
||||||
//_button.backgroundColor = 0xC0FFC0;
|
//_button.backgroundColor = 0xC0FFC0;
|
||||||
|
@ -458,7 +473,7 @@ class FilePathPanelItem : HorizontalLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Panel with buttons - path segments - for fast navigation to subdirs.
|
/// Panel with buttons - path segments - for fast navigation to subdirs.
|
||||||
class FilePathPanelButtons : WidgetGroup {
|
class FilePathPanelButtons : WidgetGroupDefaultDrawing {
|
||||||
protected string _path;
|
protected string _path;
|
||||||
Listener!OnPathSelectionHandler onPathSelectionListener;
|
Listener!OnPathSelectionHandler onPathSelectionListener;
|
||||||
protected bool onPathSelected(string path) {
|
protected bool onPathSelected(string path) {
|
||||||
|
@ -568,22 +583,6 @@ class FilePathPanelButtons : WidgetGroup {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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);
|
|
||||||
applyPadding(rc);
|
|
||||||
auto saver = ClipRectSaver(buf, rc);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Written in the D programming language.
|
||||||
|
|
||||||
|
/**
|
||||||
|
This module contains declaration of useful color related operations.
|
||||||
|
|
||||||
|
In dlangui, colors are represented as 32 bit uint AARRGGBB values.
|
||||||
|
|
||||||
|
Synopsis:
|
||||||
|
|
||||||
|
----
|
||||||
|
import dlangui.graphics.colors;
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Copyright: Vadim Lopatin, 2015
|
||||||
|
License: Boost License 1.0
|
||||||
|
Authors: Vadim Lopatin, coolreader.org@gmail.com
|
||||||
|
*/
|
||||||
|
module dlangui.graphics.colors;
|
||||||
|
|
||||||
|
private import std.string : strip;
|
||||||
|
|
||||||
|
/// special color constant to identify value as not a color (to use default/parent value instead)
|
||||||
|
immutable uint COLOR_UNSPECIFIED = 0xFFDEADFF;
|
||||||
|
/// transparent color constant
|
||||||
|
immutable uint COLOR_TRANSPARENT = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
|
||||||
|
immutable uint COLOR_TRANSFORM_OFFSET_NONE = 0x80808080;
|
||||||
|
immutable uint COLOR_TRANSFORM_MULTIPLY_NONE = 0x40404040;
|
||||||
|
|
||||||
|
uint makeRGBA(T)(T r, T g, T b, T a) {
|
||||||
|
return (cast(uint)a << 24)|(cast(uint)r << 16)|(cast(uint)g << 8)|(cast(uint)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// blend two RGB pixels using alpha
|
||||||
|
uint blendARGB(uint dst, uint src, uint alpha) {
|
||||||
|
uint dstalpha = dst >> 24;
|
||||||
|
if (dstalpha > 0x80)
|
||||||
|
return src;
|
||||||
|
uint srcr = (src >> 16) & 0xFF;
|
||||||
|
uint srcg = (src >> 8) & 0xFF;
|
||||||
|
uint srcb = (src >> 0) & 0xFF;
|
||||||
|
uint dstr = (dst >> 16) & 0xFF;
|
||||||
|
uint dstg = (dst >> 8) & 0xFF;
|
||||||
|
uint dstb = (dst >> 0) & 0xFF;
|
||||||
|
uint ialpha = 256 - alpha;
|
||||||
|
uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
|
||||||
|
uint g = ((srcg * ialpha + dstg * alpha) >> 8) & 0xFF;
|
||||||
|
uint b = ((srcb * ialpha + dstb * alpha) >> 8) & 0xFF;
|
||||||
|
return (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// blend two alpha values 0..255 (255 is fully transparent, 0 is opaque)
|
||||||
|
uint blendAlpha(uint a1, uint a2) {
|
||||||
|
if (!a1)
|
||||||
|
return a2;
|
||||||
|
if (!a2)
|
||||||
|
return a1;
|
||||||
|
return (((a1 ^ 0xFF) * (a2 ^ 0xFF)) >> 8) ^ 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// applies additional alpha to color
|
||||||
|
uint addAlpha(uint color, uint alpha) {
|
||||||
|
alpha = blendAlpha(color >> 24, alpha);
|
||||||
|
return (color & 0xFFFFFF) | (alpha << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
ubyte rgbToGray(uint color) {
|
||||||
|
uint srcr = (color >> 16) & 0xFF;
|
||||||
|
uint srcg = (color >> 8) & 0xFF;
|
||||||
|
uint srcb = (color >> 0) & 0xFF;
|
||||||
|
return cast(uint)(((srcr + srcg + srcg + srcb) >> 2) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// todo
|
||||||
|
struct ColorTransformHandler {
|
||||||
|
void init(ref ColorTransform transform) {
|
||||||
|
|
||||||
|
}
|
||||||
|
uint transform(uint color) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint transformComponent(int src, int addBefore, int multiply, int addAfter) {
|
||||||
|
int add1 = (cast(int)(addBefore << 1)) - 0x100;
|
||||||
|
int add2 = (cast(int)(addAfter << 1)) - 0x100;
|
||||||
|
int mul = cast(int)(multiply << 2);
|
||||||
|
int res = (((src + add1) * mul) >> 8) + add2;
|
||||||
|
if (res < 0)
|
||||||
|
res = 0;
|
||||||
|
else if (res > 255)
|
||||||
|
res = 255;
|
||||||
|
return cast(uint)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint transformRGBA(uint src, uint addBefore, uint multiply, uint addAfter) {
|
||||||
|
uint a = transformComponent(src >> 24, addBefore >> 24, multiply >> 24, addAfter >> 24);
|
||||||
|
uint r = transformComponent((src >> 16) & 0xFF, (addBefore >> 16) & 0xFF, (multiply >> 16) & 0xFF, (addAfter >> 16) & 0xFF);
|
||||||
|
uint g = transformComponent((src >> 8) & 0xFF, (addBefore >> 8) & 0xFF, (multiply >> 8) & 0xFF, (addAfter >> 8) & 0xFF);
|
||||||
|
uint b = transformComponent(src & 0xFF, addBefore & 0xFF, multiply & 0xFF, addAfter & 0xFF);
|
||||||
|
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ColorTransform {
|
||||||
|
uint addBefore = COLOR_TRANSFORM_OFFSET_NONE;
|
||||||
|
uint multiply = COLOR_TRANSFORM_MULTIPLY_NONE;
|
||||||
|
uint addAfter = COLOR_TRANSFORM_OFFSET_NONE;
|
||||||
|
@property bool empty() const {
|
||||||
|
return addBefore == COLOR_TRANSFORM_OFFSET_NONE
|
||||||
|
&& multiply == COLOR_TRANSFORM_MULTIPLY_NONE
|
||||||
|
&& addAfter == COLOR_TRANSFORM_OFFSET_NONE;
|
||||||
|
}
|
||||||
|
uint transform(uint color) {
|
||||||
|
return transformRGBA(color, addBefore, multiply, addAfter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// blend two RGB pixels using alpha
|
||||||
|
ubyte blendGray(ubyte dst, ubyte src, uint alpha) {
|
||||||
|
uint ialpha = 256 - alpha;
|
||||||
|
return cast(ubyte)(((src * ialpha + dst * alpha) >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns true if color is #FFxxxxxx (color alpha is 255)
|
||||||
|
bool isFullyTransparentColor(uint color) pure nothrow {
|
||||||
|
return (color >> 24) == 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// decodes hex digit (0..9, a..f, A..F), returns uint.max if invalid
|
||||||
|
uint decodeHexDigit(char ch) {
|
||||||
|
if (ch >= '0' && ch <= '9')
|
||||||
|
return ch - '0';
|
||||||
|
else if (ch >= 'a' && ch <= 'f')
|
||||||
|
return ch - 'a' + 10;
|
||||||
|
else if (ch >= 'A' && ch <= 'F')
|
||||||
|
return ch - 'A' + 10;
|
||||||
|
return uint.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// decode color string supported formats: #RGB #ARGB #RRGGBB #AARRGGBB
|
||||||
|
uint decodeHexColor(string s, uint defValue = 0) {
|
||||||
|
s = strip(s);
|
||||||
|
switch (s) {
|
||||||
|
case "@null":
|
||||||
|
case "transparent":
|
||||||
|
return COLOR_TRANSPARENT;
|
||||||
|
case "black":
|
||||||
|
return 0x000000;
|
||||||
|
case "white":
|
||||||
|
return 0xFFFFFF;
|
||||||
|
case "red":
|
||||||
|
return 0xFF0000;
|
||||||
|
case "green":
|
||||||
|
return 0x00FF00;
|
||||||
|
case "blue":
|
||||||
|
return 0x0000FF;
|
||||||
|
case "gray":
|
||||||
|
return 0x808080;
|
||||||
|
case "lightgray":
|
||||||
|
case "silver":
|
||||||
|
return 0xC0C0C0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s.length != 4 && s.length != 5 && s.length != 7 && s.length != 9)
|
||||||
|
return defValue;
|
||||||
|
if (s[0] != '#')
|
||||||
|
return defValue;
|
||||||
|
uint value = 0;
|
||||||
|
for (int i = 1; i < s.length; i++) {
|
||||||
|
uint digit = decodeHexDigit(s[i]);
|
||||||
|
if (digit == uint.max)
|
||||||
|
return defValue;
|
||||||
|
value = (value << 4) | digit;
|
||||||
|
if (s.length < 7) // double the same digit for short forms
|
||||||
|
value = (value << 4) | digit;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
|
@ -19,109 +19,8 @@ module dlangui.graphics.drawbuf;
|
||||||
|
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
|
import dlangui.graphics.colors;
|
||||||
|
|
||||||
immutable uint COLOR_TRANSFORM_OFFSET_NONE = 0x80808080;
|
|
||||||
immutable uint COLOR_TRANSFORM_MULTIPLY_NONE = 0x40404040;
|
|
||||||
|
|
||||||
uint makeRGBA(T)(T r, T g, T b, T a) {
|
|
||||||
return (cast(uint)a << 24)|(cast(uint)r << 16)|(cast(uint)g << 8)|(cast(uint)b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// blend two RGB pixels using alpha
|
|
||||||
uint blendARGB(uint dst, uint src, uint alpha) {
|
|
||||||
uint dstalpha = dst >> 24;
|
|
||||||
if (dstalpha > 0x80)
|
|
||||||
return src;
|
|
||||||
uint srcr = (src >> 16) & 0xFF;
|
|
||||||
uint srcg = (src >> 8) & 0xFF;
|
|
||||||
uint srcb = (src >> 0) & 0xFF;
|
|
||||||
uint dstr = (dst >> 16) & 0xFF;
|
|
||||||
uint dstg = (dst >> 8) & 0xFF;
|
|
||||||
uint dstb = (dst >> 0) & 0xFF;
|
|
||||||
uint ialpha = 256 - alpha;
|
|
||||||
uint r = ((srcr * ialpha + dstr * alpha) >> 8) & 0xFF;
|
|
||||||
uint g = ((srcg * ialpha + dstg * alpha) >> 8) & 0xFF;
|
|
||||||
uint b = ((srcb * ialpha + dstb * alpha) >> 8) & 0xFF;
|
|
||||||
return (r << 16) | (g << 8) | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// blend two alpha values 0..255 (255 is fully transparent, 0 is opaque)
|
|
||||||
uint blendAlpha(uint a1, uint a2) {
|
|
||||||
if (!a1)
|
|
||||||
return a2;
|
|
||||||
if (!a2)
|
|
||||||
return a1;
|
|
||||||
return (((a1 ^ 0xFF) * (a2 ^ 0xFF)) >> 8) ^ 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// applies additional alpha to color
|
|
||||||
uint addAlpha(uint color, uint alpha) {
|
|
||||||
alpha = blendAlpha(color >> 24, alpha);
|
|
||||||
return (color & 0xFFFFFF) | (alpha << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
ubyte rgbToGray(uint color) {
|
|
||||||
uint srcr = (color >> 16) & 0xFF;
|
|
||||||
uint srcg = (color >> 8) & 0xFF;
|
|
||||||
uint srcb = (color >> 0) & 0xFF;
|
|
||||||
return cast(uint)(((srcr + srcg + srcg + srcb) >> 2) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo
|
|
||||||
struct ColorTransformHandler {
|
|
||||||
void init(ref ColorTransform transform) {
|
|
||||||
|
|
||||||
}
|
|
||||||
uint transform(uint color) {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint transformComponent(int src, int addBefore, int multiply, int addAfter) {
|
|
||||||
int add1 = (cast(int)(addBefore << 1)) - 0x100;
|
|
||||||
int add2 = (cast(int)(addAfter << 1)) - 0x100;
|
|
||||||
int mul = cast(int)(multiply << 2);
|
|
||||||
int res = (((src + add1) * mul) >> 8) + add2;
|
|
||||||
if (res < 0)
|
|
||||||
res = 0;
|
|
||||||
else if (res > 255)
|
|
||||||
res = 255;
|
|
||||||
return cast(uint)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint transformRGBA(uint src, uint addBefore, uint multiply, uint addAfter) {
|
|
||||||
uint a = transformComponent(src >> 24, addBefore >> 24, multiply >> 24, addAfter >> 24);
|
|
||||||
uint r = transformComponent((src >> 16) & 0xFF, (addBefore >> 16) & 0xFF, (multiply >> 16) & 0xFF, (addAfter >> 16) & 0xFF);
|
|
||||||
uint g = transformComponent((src >> 8) & 0xFF, (addBefore >> 8) & 0xFF, (multiply >> 8) & 0xFF, (addAfter >> 8) & 0xFF);
|
|
||||||
uint b = transformComponent(src & 0xFF, addBefore & 0xFF, multiply & 0xFF, addAfter & 0xFF);
|
|
||||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ColorTransform {
|
|
||||||
uint addBefore = COLOR_TRANSFORM_OFFSET_NONE;
|
|
||||||
uint multiply = COLOR_TRANSFORM_MULTIPLY_NONE;
|
|
||||||
uint addAfter = COLOR_TRANSFORM_OFFSET_NONE;
|
|
||||||
@property bool empty() const {
|
|
||||||
return addBefore == COLOR_TRANSFORM_OFFSET_NONE
|
|
||||||
&& multiply == COLOR_TRANSFORM_MULTIPLY_NONE
|
|
||||||
&& addAfter == COLOR_TRANSFORM_OFFSET_NONE;
|
|
||||||
}
|
|
||||||
uint transform(uint color) {
|
|
||||||
return transformRGBA(color, addBefore, multiply, addAfter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// blend two RGB pixels using alpha
|
|
||||||
ubyte blendGray(ubyte dst, ubyte src, uint alpha) {
|
|
||||||
uint ialpha = 256 - alpha;
|
|
||||||
return cast(ubyte)(((src * ialpha + dst * alpha) >> 8) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns true if color is #FFxxxxxx (color alpha is 255)
|
|
||||||
bool isFullyTransparentColor(uint color) pure nothrow {
|
|
||||||
return (color >> 24) == 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 9-patch image scaling information (see Android documentation).
|
* 9-patch image scaling information (see Android documentation).
|
||||||
|
@ -411,6 +310,32 @@ class DrawBuf : RefCountedObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// draw focus rectangle; vertical gradient supported - colors[0] is top color, colors[1] is bottom color
|
||||||
|
void drawFocusRect(Rect rc, const uint[] colors) {
|
||||||
|
// override for faster performance when using OpenGL
|
||||||
|
if (colors.length < 1)
|
||||||
|
return;
|
||||||
|
uint color1 = colors[0];
|
||||||
|
uint color2 = colors.length > 1 ? colors[1] : color1;
|
||||||
|
if (isFullyTransparentColor(color1) && isFullyTransparentColor(color2))
|
||||||
|
return;
|
||||||
|
// draw horizontal lines
|
||||||
|
for (int x = rc.left; x < rc.right; x++) {
|
||||||
|
if ((x ^ rc.top) & 1)
|
||||||
|
fillRect(Rect(x, rc.top, x + 1, rc.top + 1), color1);
|
||||||
|
if ((x ^ (rc.bottom - 1)) & 1)
|
||||||
|
fillRect(Rect(x, rc.bottom - 1, x + 1, rc.bottom), color2);
|
||||||
|
}
|
||||||
|
// draw vertical lines
|
||||||
|
for (int y = rc.top + 1; y < rc.bottom - 1; y++) {
|
||||||
|
uint color = color1 == color2 ? color1 : blendARGB(color2, color1, 255 / (rc.bottom - rc.top));
|
||||||
|
if ((y ^ rc.left) & 1)
|
||||||
|
fillRect(Rect(rc.left, y, rc.left + 1, y + 1), color);
|
||||||
|
if ((y ^ (rc.right - 1)) & 1)
|
||||||
|
fillRect(Rect(rc.right - 1, y, rc.right, y + 1), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// create drawbuf with copy of current buffer with changed colors (returns this if not supported)
|
/// create drawbuf with copy of current buffer with changed colors (returns this if not supported)
|
||||||
DrawBuf transformColors(ref ColorTransform transform) {
|
DrawBuf transformColors(ref ColorTransform transform) {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -62,9 +62,9 @@ class GLDrawBuf : DrawBuf {
|
||||||
|
|
||||||
/// reserved for hardware-accelerated drawing - ends drawing batch
|
/// reserved for hardware-accelerated drawing - ends drawing batch
|
||||||
override void afterDrawing() {
|
override void afterDrawing() {
|
||||||
setOrthoProjection(_dx, _dy);
|
glSupport.setOrthoProjection(_dx, _dy);
|
||||||
_scene.draw();
|
_scene.draw();
|
||||||
flushGL();
|
glSupport.flushGL();
|
||||||
destroy(_scene);
|
destroy(_scene);
|
||||||
_scene = null;
|
_scene = null;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ private class GLImageCache {
|
||||||
_drawbuf = null;
|
_drawbuf = null;
|
||||||
}
|
}
|
||||||
if (_textureId != 0) {
|
if (_textureId != 0) {
|
||||||
deleteTexture(_textureId);
|
glSupport.deleteTexture(_textureId);
|
||||||
_textureId = 0;
|
_textureId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,14 +254,14 @@ private class GLImageCache {
|
||||||
return; // no draw buffer!!!
|
return; // no draw buffer!!!
|
||||||
if (_textureId == 0) {
|
if (_textureId == 0) {
|
||||||
//CRLog::debug("updateTexture - new texture");
|
//CRLog::debug("updateTexture - new texture");
|
||||||
_textureId = genTexture();
|
_textureId = glSupport.genTexture();
|
||||||
if (!_textureId)
|
if (!_textureId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//CRLog::debug("updateTexture - setting image %dx%d", _drawbuf.width, _drawbuf.height);
|
//CRLog::debug("updateTexture - setting image %dx%d", _drawbuf.width, _drawbuf.height);
|
||||||
uint * pixels = _drawbuf.scanLine(0);
|
uint * pixels = _drawbuf.scanLine(0);
|
||||||
if (!setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)pixels)) {
|
if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)pixels)) {
|
||||||
deleteTexture(_textureId);
|
glSupport.deleteTexture(_textureId);
|
||||||
_textureId = 0;
|
_textureId = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ private class GLImageCache {
|
||||||
if (_needUpdateTexture)
|
if (_needUpdateTexture)
|
||||||
updateTexture();
|
updateTexture();
|
||||||
if (_textureId != 0) {
|
if (_textureId != 0) {
|
||||||
if (!isTexture(_textureId)) {
|
if (!glSupport.isTexture(_textureId)) {
|
||||||
Log.e("Invalid texture ", _textureId);
|
Log.e("Invalid texture ", _textureId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -371,12 +371,12 @@ private class GLImageCache {
|
||||||
dstrc.bottom -= clip.bottom;
|
dstrc.bottom -= clip.bottom;
|
||||||
}
|
}
|
||||||
if (!dstrc.empty)
|
if (!dstrc.empty)
|
||||||
drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, srcrc.width() != dstrc.width() || srcrc.height() != dstrc.height());
|
glSupport.drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, srcrc.width() != dstrc.width() || srcrc.height() != dstrc.height());
|
||||||
//drawColorAndTextureRect(vertices, texcoords, color, _textureId);
|
//drawColorAndTextureRect(vertices, texcoords, color, _textureId);
|
||||||
|
|
||||||
if (rotationAngle) {
|
if (rotationAngle) {
|
||||||
// unset rotation
|
// unset rotation
|
||||||
setRotation(rx, ry, 0);
|
glSupport.setRotation(rx, ry, 0);
|
||||||
// glMatrixMode(GL_PROJECTION);
|
// glMatrixMode(GL_PROJECTION);
|
||||||
// glPopMatrix();
|
// glPopMatrix();
|
||||||
// checkError("pop matrix");
|
// checkError("pop matrix");
|
||||||
|
@ -576,7 +576,7 @@ private class GLGlyphCache {
|
||||||
_drawbuf = null;
|
_drawbuf = null;
|
||||||
}
|
}
|
||||||
if (_textureId != 0) {
|
if (_textureId != 0) {
|
||||||
deleteTexture(_textureId);
|
glSupport.deleteTexture(_textureId);
|
||||||
_textureId = 0;
|
_textureId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,7 +589,7 @@ private class GLGlyphCache {
|
||||||
return; // no draw buffer!!!
|
return; // no draw buffer!!!
|
||||||
if (_textureId == 0) {
|
if (_textureId == 0) {
|
||||||
//CRLog::debug("updateTexture - new texture");
|
//CRLog::debug("updateTexture - new texture");
|
||||||
_textureId = genTexture();
|
_textureId = glSupport.genTexture();
|
||||||
if (!_textureId)
|
if (!_textureId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -600,8 +600,8 @@ private class GLGlyphCache {
|
||||||
_rgbaBuffer.length = len;
|
_rgbaBuffer.length = len;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
_rgbaBuffer[i] = ((cast(uint)pixels[i]) << 24) | 0x00FFFFFF;
|
_rgbaBuffer[i] = ((cast(uint)pixels[i]) << 24) | 0x00FFFFFF;
|
||||||
if (!setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)_rgbaBuffer.ptr)) {
|
if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)_rgbaBuffer.ptr)) {
|
||||||
deleteTexture(_textureId);
|
glSupport.deleteTexture(_textureId);
|
||||||
_textureId = 0;
|
_textureId = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -667,7 +667,7 @@ private class GLGlyphCache {
|
||||||
if (_needUpdateTexture)
|
if (_needUpdateTexture)
|
||||||
updateTexture();
|
updateTexture();
|
||||||
if (_textureId != 0) {
|
if (_textureId != 0) {
|
||||||
if (!isTexture(_textureId)) {
|
if (!glSupport.isTexture(_textureId)) {
|
||||||
Log.e("Invalid texture ", _textureId);
|
Log.e("Invalid texture ", _textureId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -693,7 +693,7 @@ private class GLGlyphCache {
|
||||||
}
|
}
|
||||||
if (!dstrc.empty) {
|
if (!dstrc.empty) {
|
||||||
//Log.d("drawing glyph with color ", color);
|
//Log.d("drawing glyph with color ", color);
|
||||||
drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, false);
|
glSupport.drawColorAndTextureRect(_textureId, _tdx, _tdy, srcrc, dstrc, color, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -818,7 +818,7 @@ class SolidRectSceneItem : SceneItem {
|
||||||
_color = color;
|
_color = color;
|
||||||
}
|
}
|
||||||
override void draw() {
|
override void draw() {
|
||||||
drawSolidFillRect(_rc, _color, _color, _color, _color);
|
glSupport.drawSolidFillRect(_rc, _color, _color, _color, _color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,8 @@ static this() {
|
||||||
0x0505: "GL_OUT_OF_MEMORY"
|
0x0505: "GL_OUT_OF_MEMORY"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/* Convenient wrapper around glGetError()
|
/**
|
||||||
|
* Convenient wrapper around glGetError()
|
||||||
* TODO use one of the DEBUG extensions instead
|
* TODO use one of the DEBUG extensions instead
|
||||||
*/
|
*/
|
||||||
bool checkError(string context="", string file=__FILE__, int line=__LINE__)
|
bool checkError(string context="", string file=__FILE__, int line=__LINE__)
|
||||||
|
@ -67,7 +68,427 @@ bool checkError(string context="", string file=__FILE__, int line=__LINE__)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
immutable float Z_2D = -2.0f;
|
|
||||||
|
class GLProgram {
|
||||||
|
@property abstract string vertexSource();
|
||||||
|
@property abstract string fragmentSource();
|
||||||
|
protected GLuint vertexShader;
|
||||||
|
protected GLuint fragmentShader;
|
||||||
|
protected GLuint program;
|
||||||
|
protected bool initialized;
|
||||||
|
protected bool error;
|
||||||
|
protected string glslversion;
|
||||||
|
this() {
|
||||||
|
}
|
||||||
|
private GLuint compileShader(string src, GLuint type) {
|
||||||
|
import core.stdc.stdlib;
|
||||||
|
import std.string;
|
||||||
|
|
||||||
|
Log.d("compileShader glsl=", glslversion, " code: ", src);
|
||||||
|
|
||||||
|
GLuint shader = glCreateShader(type);//GL_VERTEX_SHADER
|
||||||
|
const char * psrc = src.toStringz;
|
||||||
|
GLuint len = cast(uint)src.length;
|
||||||
|
glShaderSource(shader, 1, &psrc, cast(const(int)*)&len);
|
||||||
|
glCompileShader(shader);
|
||||||
|
GLint compiled;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
||||||
|
if (compiled) {
|
||||||
|
// compiled successfully
|
||||||
|
return shader;
|
||||||
|
} else {
|
||||||
|
GLint blen = 0;
|
||||||
|
GLsizei slen = 0;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &blen);
|
||||||
|
if (blen > 1)
|
||||||
|
{
|
||||||
|
GLchar[] msg = new GLchar[blen + 1];
|
||||||
|
GLchar * pmsg = &msg[0];
|
||||||
|
glGetShaderInfoLog(shader, blen, &slen, pmsg);
|
||||||
|
Log.d("Shader compilation error: ", fromStringz(pmsg));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool compile() {
|
||||||
|
glslversion = cast(string)std.string.fromStringz(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
|
vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER);
|
||||||
|
fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER);
|
||||||
|
if (!vertexShader || !fragmentShader) {
|
||||||
|
error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
program = glCreateProgram();
|
||||||
|
glAttachShader(program, vertexShader);
|
||||||
|
glAttachShader(program, fragmentShader);
|
||||||
|
glLinkProgram(program);
|
||||||
|
GLint isLinked = 0;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
|
||||||
|
if (!isLinked) {
|
||||||
|
GLint maxLength = 0;
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
|
||||||
|
GLchar[] msg = new GLchar[maxLength + 1];
|
||||||
|
GLchar * pmsg = &msg[0];
|
||||||
|
glGetProgramInfoLog(program, maxLength, &maxLength, pmsg);
|
||||||
|
Log.e("Error while linking program: ", fromStringz(pmsg));
|
||||||
|
error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.d("Program compiled successfully");
|
||||||
|
//glDetachShader(program, vertexShader);
|
||||||
|
//glDetachShader(program, fragmentShader);
|
||||||
|
glUseProgram(program);
|
||||||
|
checkError("glUseProgram " ~ to!string(program));
|
||||||
|
if (!initLocations()) {
|
||||||
|
Log.e("some of locations were not found");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool initLocations() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool bind() {
|
||||||
|
if (!initialized)
|
||||||
|
return false;
|
||||||
|
if (!glIsProgram(program))
|
||||||
|
Log.e("!glIsProgram(program)");
|
||||||
|
glUseProgram(program);
|
||||||
|
checkError("glUseProgram " ~ to!string(program));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void release() {
|
||||||
|
glUseProgram(0);
|
||||||
|
checkError("glUseProgram(0)");
|
||||||
|
}
|
||||||
|
~this() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
// TODO: cleanup
|
||||||
|
if (program)
|
||||||
|
glDeleteProgram(program);
|
||||||
|
if (vertexShader)
|
||||||
|
glDeleteShader(vertexShader);
|
||||||
|
if (fragmentShader)
|
||||||
|
glDeleteShader(fragmentShader);
|
||||||
|
program = vertexShader = fragmentShader = 0;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
immutable string HIGHP = "";
|
||||||
|
immutable string LOWP = "";
|
||||||
|
immutable string MEDIUMP = "";
|
||||||
|
|
||||||
|
class SolidFillProgram : GLProgram {
|
||||||
|
@property override string vertexSource() {
|
||||||
|
return
|
||||||
|
"attribute " ~ HIGHP ~ " vec4 vertex;\n"
|
||||||
|
"attribute " ~ LOWP ~ " vec4 colAttr;\n"
|
||||||
|
"varying " ~ LOWP ~ " vec4 col;\n"
|
||||||
|
"uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
|
||||||
|
"void main(void)\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_Position = matrix * vertex;\n"
|
||||||
|
" col = colAttr;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
@property override string fragmentSource() {
|
||||||
|
return
|
||||||
|
"varying " ~ LOWP ~ " vec4 col;\n"
|
||||||
|
"void main(void)\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_FragColor = col;\n"
|
||||||
|
"}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void beforeExecute() {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
checkError("glDisable(GL_CULL_FACE)");
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
|
||||||
|
bind();
|
||||||
|
//glUniformMatrix4fv(matrixLocation, 1, false, m.value_ptr);
|
||||||
|
//glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr);
|
||||||
|
glUniformMatrix4fv(matrixLocation, 1, false, glSupport.qtmatrix.ptr);
|
||||||
|
checkError("glUniformMatrix4fv");
|
||||||
|
}
|
||||||
|
|
||||||
|
void afterExecute() {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GLint matrixLocation;
|
||||||
|
protected GLint vertexLocation;
|
||||||
|
protected GLint colAttrLocation;
|
||||||
|
protected GLuint vertexBuffer;
|
||||||
|
protected GLuint colAttrBuffer;
|
||||||
|
override bool initLocations() {
|
||||||
|
bool res = super.initLocations();
|
||||||
|
|
||||||
|
//glGenBuffers(1, &vertexBuffer);
|
||||||
|
//glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
||||||
|
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 3 * 6, null, GL_DYNAMIC_DRAW);
|
||||||
|
//glGenBuffers(1, &colAttrBuffer);
|
||||||
|
//glBindBuffer(GL_ARRAY_BUFFER, colAttrBuffer);
|
||||||
|
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 4 * 6, null, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
matrixLocation = glGetUniformLocation(program, "matrix");
|
||||||
|
checkError("glGetUniformLocation matrix");
|
||||||
|
vertexLocation = glGetAttribLocation(program, "vertex");
|
||||||
|
checkError("glGetAttribLocation vertex");
|
||||||
|
colAttrLocation = glGetAttribLocation(program, "colAttr");
|
||||||
|
checkError("glGetAttribLocation colAttr");
|
||||||
|
return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(float[] vertices, float[] colors) {
|
||||||
|
if (error)
|
||||||
|
return false;
|
||||||
|
if (!initialized)
|
||||||
|
if (!compile())
|
||||||
|
return false;
|
||||||
|
beforeExecute();
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
|
||||||
|
null,
|
||||||
|
GL_STREAM_DRAW);
|
||||||
|
glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
0,
|
||||||
|
vertices.length * vertices[0].sizeof,
|
||||||
|
vertices.ptr);
|
||||||
|
glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
vertices.length * vertices[0].sizeof,
|
||||||
|
colors.length * colors[0].sizeof, colors.ptr);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(vertexLocation);
|
||||||
|
checkError("glEnableVertexAttribArray");
|
||||||
|
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
|
||||||
|
checkError("glVertexAttribPointer");
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(colAttrLocation);
|
||||||
|
checkError("glEnableVertexAttribArray");
|
||||||
|
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*6));
|
||||||
|
checkError("glVertexAttribPointer");
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
checkError("glDrawArrays");
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(vertexLocation);
|
||||||
|
checkError("glDisableVertexAttribArray");
|
||||||
|
glDisableVertexAttribArray(colAttrLocation);
|
||||||
|
checkError("glDisableVertexAttribArray");
|
||||||
|
|
||||||
|
afterExecute();
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glDeleteBuffers(1, &vbo);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextureProgram : SolidFillProgram {
|
||||||
|
@property override string vertexSource() {
|
||||||
|
return
|
||||||
|
"attribute " ~ HIGHP ~ " vec4 vertex;\n"
|
||||||
|
"attribute " ~ LOWP ~ " vec4 colAttr;\n"
|
||||||
|
"attribute " ~ MEDIUMP ~ " vec4 texCoord;\n"
|
||||||
|
"varying " ~ LOWP ~ " vec4 col;\n"
|
||||||
|
"varying " ~ MEDIUMP ~ " vec4 texc;\n"
|
||||||
|
"uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
|
||||||
|
"void main(void)\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_Position = matrix * vertex;\n"
|
||||||
|
" col = colAttr;\n"
|
||||||
|
" texc = texCoord;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
@property override string fragmentSource() {
|
||||||
|
return
|
||||||
|
"uniform sampler2D texture;\n"
|
||||||
|
"varying " ~ LOWP ~ " vec4 col;\n"
|
||||||
|
"varying " ~ MEDIUMP ~ " vec4 texc;\n"
|
||||||
|
"void main(void)\n"
|
||||||
|
"{\n"
|
||||||
|
" gl_FragColor = texture2D(texture, texc.st) * col;\n"
|
||||||
|
"}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint texCoordLocation;
|
||||||
|
override bool initLocations() {
|
||||||
|
bool res = super.initLocations();
|
||||||
|
texCoordLocation = glGetAttribLocation(program, "texCoord");
|
||||||
|
return res && texCoordLocation >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute(float[] vertices, float[] texcoords, float[] colors, uint textureId, bool linear) {
|
||||||
|
if (error)
|
||||||
|
return false;
|
||||||
|
if (!initialized)
|
||||||
|
if (!compile())
|
||||||
|
return false;
|
||||||
|
beforeExecute();
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
checkError("glActiveTexture GL_TEXTURE0");
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||||
|
checkError("glBindTexture");
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||||
|
checkError("drawColorAndTextureRect - glTexParameteri");
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||||
|
checkError("drawColorAndTextureRect - glTexParameteri");
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
vertices.length * vertices[0].sizeof +
|
||||||
|
colors.length * colors[0].sizeof +
|
||||||
|
texcoords.length * texcoords[0].sizeof,
|
||||||
|
null,
|
||||||
|
GL_STREAM_DRAW);
|
||||||
|
glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
0,
|
||||||
|
vertices.length * vertices[0].sizeof,
|
||||||
|
vertices.ptr);
|
||||||
|
glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
vertices.length * vertices[0].sizeof,
|
||||||
|
colors.length * colors[0].sizeof,
|
||||||
|
colors.ptr);
|
||||||
|
glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER,
|
||||||
|
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
|
||||||
|
texcoords.length * texcoords[0].sizeof,
|
||||||
|
texcoords.ptr);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(vertexLocation);
|
||||||
|
glEnableVertexAttribArray(colAttrLocation);
|
||||||
|
glEnableVertexAttribArray(texCoordLocation);
|
||||||
|
|
||||||
|
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
|
||||||
|
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof));
|
||||||
|
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof));
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
checkError("glDrawArrays");
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(vertexLocation);
|
||||||
|
glDisableVertexAttribArray(colAttrLocation);
|
||||||
|
glDisableVertexAttribArray(texCoordLocation);
|
||||||
|
|
||||||
|
afterExecute();
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glDeleteBuffers(1, &vbo);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
checkError("glBindTexture");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__gshared GLSupport _glSupport;
|
||||||
|
@property GLSupport glSupport() {
|
||||||
|
if (!_glSupport) {
|
||||||
|
Log.f("GLSupport is not initialized");
|
||||||
|
assert(false, "GLSupport is not initialized");
|
||||||
|
}
|
||||||
|
if (!_glSupport.valid) {
|
||||||
|
Log.e("GLSupport programs are not initialized");
|
||||||
|
}
|
||||||
|
return _glSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GLSupport {
|
||||||
|
|
||||||
|
TextureProgram _textureProgram;
|
||||||
|
SolidFillProgram _solidFillProgram;
|
||||||
|
|
||||||
|
@property bool valid() {
|
||||||
|
return _textureProgram && _solidFillProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initShaders() {
|
||||||
|
if (_textureProgram is null) {
|
||||||
|
_textureProgram = new TextureProgram();
|
||||||
|
if (!_textureProgram.compile())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_solidFillProgram is null) {
|
||||||
|
_solidFillProgram = new SolidFillProgram();
|
||||||
|
if (!_solidFillProgram.compile())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.d("Shaders compiled successfully");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uninitShaders() {
|
||||||
|
Log.d("Uniniting shaders");
|
||||||
|
if (_textureProgram !is null) {
|
||||||
|
destroy(_textureProgram);
|
||||||
|
_textureProgram = null;
|
||||||
|
}
|
||||||
|
if (_solidFillProgram !is null) {
|
||||||
|
destroy(_solidFillProgram);
|
||||||
|
_solidFillProgram = null;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTexture(uint textureId) {
|
||||||
|
return glIsTexture(textureId) == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRotation(int x, int y, int rotationAngle) {
|
||||||
|
/*
|
||||||
|
this->rotationAngle = rotationAngle;
|
||||||
|
rotationX = x;
|
||||||
|
rotationY = y;
|
||||||
|
if (!currentFramebufferId) {
|
||||||
|
rotationY = bufferDy - rotationY;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMatrix4x4 matrix2;
|
||||||
|
matrix2.ortho(0, bufferDx, 0, bufferDy, 0.5f, 5.0f);
|
||||||
|
if (rotationAngle) {
|
||||||
|
matrix2.translate(rotationX, rotationY, 0);
|
||||||
|
matrix2.rotate(rotationAngle, 0, 0, 1);
|
||||||
|
matrix2.translate(-rotationX, -rotationY, 0);
|
||||||
|
}
|
||||||
|
matrix2.copyDataTo(m);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
static immutable float Z_2D = -2.0f;
|
||||||
void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||||
float[6 * 4] colors;
|
float[6 * 4] colors;
|
||||||
LVGLFillColor(color1, colors.ptr + 4*0, 1);
|
LVGLFillColor(color1, colors.ptr + 4*0, 1);
|
||||||
|
@ -313,7 +734,6 @@ bool bindFramebuffer(uint framebufferId) {
|
||||||
private int bufferDx;
|
private int bufferDx;
|
||||||
/// current gl buffer height
|
/// current gl buffer height
|
||||||
private int bufferDy;
|
private int bufferDy;
|
||||||
|
|
||||||
//private float[16] matrix;
|
//private float[16] matrix;
|
||||||
private float[16] qtmatrix;
|
private float[16] qtmatrix;
|
||||||
|
|
||||||
|
@ -357,404 +777,5 @@ void setOrthoProjection(int dx, int dy) {
|
||||||
checkError("glViewport");
|
checkError("glViewport");
|
||||||
}
|
}
|
||||||
|
|
||||||
class GLProgram {
|
|
||||||
@property abstract string vertexSource();
|
|
||||||
@property abstract string fragmentSource();
|
|
||||||
protected GLuint vertexShader;
|
|
||||||
protected GLuint fragmentShader;
|
|
||||||
protected GLuint program;
|
|
||||||
protected bool initialized;
|
|
||||||
protected bool error;
|
|
||||||
protected string glslversion;
|
|
||||||
this() {
|
|
||||||
}
|
|
||||||
private GLuint compileShader(string src, GLuint type) {
|
|
||||||
import core.stdc.stdlib;
|
|
||||||
import std.string;
|
|
||||||
|
|
||||||
Log.d("compileShader glsl=", glslversion, " code: ", src);
|
|
||||||
|
|
||||||
GLuint shader = glCreateShader(type);//GL_VERTEX_SHADER
|
|
||||||
const char * psrc = src.toStringz;
|
|
||||||
GLuint len = cast(uint)src.length;
|
|
||||||
glShaderSource(shader, 1, &psrc, cast(const(int)*)&len);
|
|
||||||
glCompileShader(shader);
|
|
||||||
GLint compiled;
|
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
|
|
||||||
if (compiled) {
|
|
||||||
// compiled successfully
|
|
||||||
return shader;
|
|
||||||
} else {
|
|
||||||
GLint blen = 0;
|
|
||||||
GLsizei slen = 0;
|
|
||||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &blen);
|
|
||||||
if (blen > 1)
|
|
||||||
{
|
|
||||||
GLchar[] msg = new GLchar[blen + 1];
|
|
||||||
GLchar * pmsg = &msg[0];
|
|
||||||
glGetShaderInfoLog(shader, blen, &slen, pmsg);
|
|
||||||
Log.d("Shader compilation error: ", fromStringz(pmsg));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool compile() {
|
|
||||||
glslversion = cast(string)std.string.fromStringz(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
||||||
vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER);
|
|
||||||
fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER);
|
|
||||||
if (!vertexShader || !fragmentShader) {
|
|
||||||
error = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
program = glCreateProgram();
|
|
||||||
glAttachShader(program, vertexShader);
|
|
||||||
glAttachShader(program, fragmentShader);
|
|
||||||
glLinkProgram(program);
|
|
||||||
GLint isLinked = 0;
|
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
|
|
||||||
if (!isLinked) {
|
|
||||||
GLint maxLength = 0;
|
|
||||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
|
|
||||||
GLchar[] msg = new GLchar[maxLength + 1];
|
|
||||||
GLchar * pmsg = &msg[0];
|
|
||||||
glGetProgramInfoLog(program, maxLength, &maxLength, pmsg);
|
|
||||||
Log.e("Error while linking program: ", fromStringz(pmsg));
|
|
||||||
error = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Log.d("Program compiled successfully");
|
|
||||||
//glDetachShader(program, vertexShader);
|
|
||||||
//glDetachShader(program, fragmentShader);
|
|
||||||
glUseProgram(program);
|
|
||||||
checkError("glUseProgram " ~ to!string(program));
|
|
||||||
if (!initLocations()) {
|
|
||||||
Log.e("some of locations were not found");
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool initLocations() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool bind() {
|
|
||||||
if (!initialized)
|
|
||||||
return false;
|
|
||||||
if (!glIsProgram(program))
|
|
||||||
Log.e("!glIsProgram(program)");
|
|
||||||
glUseProgram(program);
|
|
||||||
checkError("glUseProgram " ~ to!string(program));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void release() {
|
|
||||||
glUseProgram(0);
|
|
||||||
checkError("glUseProgram(0)");
|
|
||||||
}
|
|
||||||
~this() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
void clear() {
|
|
||||||
// TODO: cleanup
|
|
||||||
if (program)
|
|
||||||
glDeleteProgram(program);
|
|
||||||
if (vertexShader)
|
|
||||||
glDeleteShader(vertexShader);
|
|
||||||
if (fragmentShader)
|
|
||||||
glDeleteShader(fragmentShader);
|
|
||||||
program = vertexShader = fragmentShader = 0;
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
immutable string HIGHP = "";
|
|
||||||
immutable string LOWP = "";
|
|
||||||
immutable string MEDIUMP = "";
|
|
||||||
|
|
||||||
class SolidFillProgram : GLProgram {
|
|
||||||
@property override string vertexSource() {
|
|
||||||
return
|
|
||||||
"attribute " ~ HIGHP ~ " vec4 vertex;\n"
|
|
||||||
"attribute " ~ LOWP ~ " vec4 colAttr;\n"
|
|
||||||
"varying " ~ LOWP ~ " vec4 col;\n"
|
|
||||||
"uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" gl_Position = matrix * vertex;\n"
|
|
||||||
" col = colAttr;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
}
|
|
||||||
@property override string fragmentSource() {
|
|
||||||
return
|
|
||||||
"varying " ~ LOWP ~ " vec4 col;\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" gl_FragColor = col;\n"
|
|
||||||
"}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void beforeExecute() {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
checkError("glDisable(GL_CULL_FACE)");
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
//glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
||||||
checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
|
|
||||||
bind();
|
|
||||||
//glUniformMatrix4fv(matrixLocation, 1, false, m.value_ptr);
|
|
||||||
//glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr);
|
|
||||||
glUniformMatrix4fv(matrixLocation, 1, false, qtmatrix.ptr);
|
|
||||||
checkError("glUniformMatrix4fv");
|
|
||||||
}
|
|
||||||
|
|
||||||
void afterExecute() {
|
|
||||||
release();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected GLint matrixLocation;
|
|
||||||
protected GLint vertexLocation;
|
|
||||||
protected GLint colAttrLocation;
|
|
||||||
protected GLuint vertexBuffer;
|
|
||||||
protected GLuint colAttrBuffer;
|
|
||||||
override bool initLocations() {
|
|
||||||
bool res = super.initLocations();
|
|
||||||
|
|
||||||
//glGenBuffers(1, &vertexBuffer);
|
|
||||||
//glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
||||||
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 3 * 6, null, GL_DYNAMIC_DRAW);
|
|
||||||
//glGenBuffers(1, &colAttrBuffer);
|
|
||||||
//glBindBuffer(GL_ARRAY_BUFFER, colAttrBuffer);
|
|
||||||
//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 4 * 6, null, GL_DYNAMIC_DRAW);
|
|
||||||
|
|
||||||
matrixLocation = glGetUniformLocation(program, "matrix");
|
|
||||||
checkError("glGetUniformLocation matrix");
|
|
||||||
vertexLocation = glGetAttribLocation(program, "vertex");
|
|
||||||
checkError("glGetAttribLocation vertex");
|
|
||||||
colAttrLocation = glGetAttribLocation(program, "colAttr");
|
|
||||||
checkError("glGetAttribLocation colAttr");
|
|
||||||
return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool execute(float[] vertices, float[] colors) {
|
|
||||||
if (error)
|
|
||||||
return false;
|
|
||||||
if (!initialized)
|
|
||||||
if (!compile())
|
|
||||||
return false;
|
|
||||||
beforeExecute();
|
|
||||||
|
|
||||||
GLuint vao;
|
|
||||||
glGenVertexArrays(1, &vao);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
GLuint vbo;
|
|
||||||
glGenBuffers(1, &vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
glBufferData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
|
|
||||||
null,
|
|
||||||
GL_STREAM_DRAW);
|
|
||||||
glBufferSubData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
0,
|
|
||||||
vertices.length * vertices[0].sizeof,
|
|
||||||
vertices.ptr);
|
|
||||||
glBufferSubData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
vertices.length * vertices[0].sizeof,
|
|
||||||
colors.length * colors[0].sizeof, colors.ptr);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(vertexLocation);
|
|
||||||
checkError("glEnableVertexAttribArray");
|
|
||||||
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
|
|
||||||
checkError("glVertexAttribPointer");
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(colAttrLocation);
|
|
||||||
checkError("glEnableVertexAttribArray");
|
|
||||||
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*6));
|
|
||||||
checkError("glVertexAttribPointer");
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
checkError("glDrawArrays");
|
|
||||||
|
|
||||||
glDisableVertexAttribArray(vertexLocation);
|
|
||||||
checkError("glDisableVertexAttribArray");
|
|
||||||
glDisableVertexAttribArray(colAttrLocation);
|
|
||||||
checkError("glDisableVertexAttribArray");
|
|
||||||
|
|
||||||
afterExecute();
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glDeleteBuffers(1, &vbo);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glDeleteVertexArrays(1, &vao);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TextureProgram : SolidFillProgram {
|
|
||||||
@property override string vertexSource() {
|
|
||||||
return
|
|
||||||
"attribute " ~ HIGHP ~ " vec4 vertex;\n"
|
|
||||||
"attribute " ~ LOWP ~ " vec4 colAttr;\n"
|
|
||||||
"attribute " ~ MEDIUMP ~ " vec4 texCoord;\n"
|
|
||||||
"varying " ~ LOWP ~ " vec4 col;\n"
|
|
||||||
"varying " ~ MEDIUMP ~ " vec4 texc;\n"
|
|
||||||
"uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" gl_Position = matrix * vertex;\n"
|
|
||||||
" col = colAttr;\n"
|
|
||||||
" texc = texCoord;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
}
|
|
||||||
@property override string fragmentSource() {
|
|
||||||
return
|
|
||||||
"uniform sampler2D texture;\n"
|
|
||||||
"varying " ~ LOWP ~ " vec4 col;\n"
|
|
||||||
"varying " ~ MEDIUMP ~ " vec4 texc;\n"
|
|
||||||
"void main(void)\n"
|
|
||||||
"{\n"
|
|
||||||
" gl_FragColor = texture2D(texture, texc.st) * col;\n"
|
|
||||||
"}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint texCoordLocation;
|
|
||||||
override bool initLocations() {
|
|
||||||
bool res = super.initLocations();
|
|
||||||
texCoordLocation = glGetAttribLocation(program, "texCoord");
|
|
||||||
return res && texCoordLocation >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool execute(float[] vertices, float[] texcoords, float[] colors, uint textureId, bool linear) {
|
|
||||||
if (error)
|
|
||||||
return false;
|
|
||||||
if (!initialized)
|
|
||||||
if (!compile())
|
|
||||||
return false;
|
|
||||||
beforeExecute();
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
checkError("glActiveTexture GL_TEXTURE0");
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
|
||||||
checkError("glBindTexture");
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
|
||||||
checkError("drawColorAndTextureRect - glTexParameteri");
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
|
||||||
checkError("drawColorAndTextureRect - glTexParameteri");
|
|
||||||
|
|
||||||
GLuint vao;
|
|
||||||
glGenVertexArrays(1, &vao);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
GLuint vbo;
|
|
||||||
glGenBuffers(1, &vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
glBufferData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
vertices.length * vertices[0].sizeof +
|
|
||||||
colors.length * colors[0].sizeof +
|
|
||||||
texcoords.length * texcoords[0].sizeof,
|
|
||||||
null,
|
|
||||||
GL_STREAM_DRAW);
|
|
||||||
glBufferSubData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
0,
|
|
||||||
vertices.length * vertices[0].sizeof,
|
|
||||||
vertices.ptr);
|
|
||||||
glBufferSubData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
vertices.length * vertices[0].sizeof,
|
|
||||||
colors.length * colors[0].sizeof,
|
|
||||||
colors.ptr);
|
|
||||||
glBufferSubData(
|
|
||||||
GL_ARRAY_BUFFER,
|
|
||||||
vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof,
|
|
||||||
texcoords.length * texcoords[0].sizeof,
|
|
||||||
texcoords.ptr);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(vertexLocation);
|
|
||||||
glEnableVertexAttribArray(colAttrLocation);
|
|
||||||
glEnableVertexAttribArray(texCoordLocation);
|
|
||||||
|
|
||||||
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0);
|
|
||||||
glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof));
|
|
||||||
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof));
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
checkError("glDrawArrays");
|
|
||||||
|
|
||||||
glDisableVertexAttribArray(vertexLocation);
|
|
||||||
glDisableVertexAttribArray(colAttrLocation);
|
|
||||||
glDisableVertexAttribArray(texCoordLocation);
|
|
||||||
|
|
||||||
afterExecute();
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glDeleteBuffers(1, &vbo);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glDeleteVertexArrays(1, &vao);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
checkError("glBindTexture");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__gshared TextureProgram _textureProgram;
|
|
||||||
__gshared SolidFillProgram _solidFillProgram;
|
|
||||||
|
|
||||||
bool initShaders() {
|
|
||||||
if (_textureProgram is null) {
|
|
||||||
_textureProgram = new TextureProgram();
|
|
||||||
if (!_textureProgram.compile())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (_solidFillProgram is null) {
|
|
||||||
_solidFillProgram = new SolidFillProgram();
|
|
||||||
if (!_solidFillProgram.compile())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Log.d("Shaders compiled successfully");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uninitShaders() {
|
|
||||||
Log.d("Uniniting shaders");
|
|
||||||
if (_textureProgram !is null) {
|
|
||||||
destroy(_textureProgram);
|
|
||||||
_textureProgram = null;
|
|
||||||
}
|
|
||||||
if (_solidFillProgram !is null) {
|
|
||||||
destroy(_solidFillProgram);
|
|
||||||
_solidFillProgram = null;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTexture(uint textureId) {
|
|
||||||
return glIsTexture(textureId) == GL_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRotation(int x, int y, int rotationAngle) {
|
|
||||||
/*
|
|
||||||
this->rotationAngle = rotationAngle;
|
|
||||||
rotationX = x;
|
|
||||||
rotationY = y;
|
|
||||||
if (!currentFramebufferId) {
|
|
||||||
rotationY = bufferDy - rotationY;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMatrix4x4 matrix2;
|
|
||||||
matrix2.ortho(0, bufferDx, 0, bufferDy, 0.5f, 5.0f);
|
|
||||||
if (rotationAngle) {
|
|
||||||
matrix2.translate(rotationX, rotationY, 0);
|
|
||||||
matrix2.rotate(rotationAngle, 0, 0, 1);
|
|
||||||
matrix2.translate(-rotationX, -rotationY, 0);
|
|
||||||
}
|
|
||||||
matrix2.copyDataTo(m);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ version (USE_DLIBIMAGE) {
|
||||||
|
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
import dlangui.core.types;
|
import dlangui.core.types;
|
||||||
|
import dlangui.graphics.colors;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import std.stream;
|
import std.stream;
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
|
|
|
@ -28,6 +28,7 @@ module dlangui.graphics.resources;
|
||||||
|
|
||||||
import dlangui.graphics.images;
|
import dlangui.graphics.images;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
|
import dlangui.graphics.colors;
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
import std.file;
|
import std.file;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
|
@ -93,22 +94,7 @@ class FrameDrawable : Drawable {
|
||||||
@property override Rect padding() { return _frameWidths; }
|
@property override Rect padding() { return _frameWidths; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// decode color string #AARRGGBB, e.g. #5599AA
|
|
||||||
static uint decodeHexColor(string s) {
|
|
||||||
uint value = 0;
|
|
||||||
foreach(c; s) {
|
|
||||||
int digit = -1;
|
|
||||||
if (c >='0' && c <= '9')
|
|
||||||
digit = c - '0';
|
|
||||||
else if (c >='a' && c <= 'f')
|
|
||||||
digit = c - 'a' + 10;
|
|
||||||
else if (c >='A' && c <= 'F')
|
|
||||||
digit = c - 'A' + 10;
|
|
||||||
if (digit >= 0)
|
|
||||||
value = (value << 4) | digit;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
/// decode size string, e.g. 1px or 2 or 3pt
|
/// decode size string, e.g. 1px or 2 or 3pt
|
||||||
static uint decodeDimension(string s) {
|
static uint decodeDimension(string s) {
|
||||||
uint value = 0;
|
uint value = 0;
|
||||||
|
@ -348,6 +334,7 @@ void extractStateFlag(ref string[string] attr, string attrName, string attrName2
|
||||||
void extractStateFlags(ref string[string] attr, ref uint stateMask, ref uint stateValue) {
|
void extractStateFlags(ref string[string] attr, ref uint stateMask, ref uint stateValue) {
|
||||||
extractStateFlag(attr, "state_pressed", "android:state_pressed", State.Pressed, stateMask, stateValue);
|
extractStateFlag(attr, "state_pressed", "android:state_pressed", State.Pressed, stateMask, stateValue);
|
||||||
extractStateFlag(attr, "state_focused", "android:state_focused", State.Focused, stateMask, stateValue);
|
extractStateFlag(attr, "state_focused", "android:state_focused", State.Focused, stateMask, stateValue);
|
||||||
|
extractStateFlag(attr, "state_default", "android:state_default", State.Default, stateMask, stateValue);
|
||||||
extractStateFlag(attr, "state_hovered", "android:state_hovered", State.Hovered, stateMask, stateValue);
|
extractStateFlag(attr, "state_hovered", "android:state_hovered", State.Hovered, stateMask, stateValue);
|
||||||
extractStateFlag(attr, "state_selected", "android:state_selected", State.Selected, stateMask, stateValue);
|
extractStateFlag(attr, "state_selected", "android:state_selected", State.Selected, stateMask, stateValue);
|
||||||
extractStateFlag(attr, "state_checkable", "android:state_checkable", State.Checkable, stateMask, stateValue);
|
extractStateFlag(attr, "state_checkable", "android:state_checkable", State.Checkable, stateMask, stateValue);
|
||||||
|
|
|
@ -107,11 +107,13 @@ class Window {
|
||||||
Log.d("onResize ", _dx, "x", _dy);
|
Log.d("onResize ", _dx, "x", _dy);
|
||||||
long measureStart = currentTimeMillis;
|
long measureStart = currentTimeMillis;
|
||||||
measure();
|
measure();
|
||||||
|
//Log.d("measured size: ", _mainWidget.measuredWidth, "x", _mainWidget.measuredHeight);
|
||||||
long measureEnd = currentTimeMillis;
|
long measureEnd = currentTimeMillis;
|
||||||
Log.d("measure took ", measureEnd - measureStart, " ms");
|
Log.d("measure took ", measureEnd - measureStart, " ms");
|
||||||
layout();
|
layout();
|
||||||
long layoutEnd = currentTimeMillis;
|
long layoutEnd = currentTimeMillis;
|
||||||
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
||||||
|
//Log.d("layout position: ", _mainWidget.pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,8 @@ class SDLWindow : Window {
|
||||||
version(USE_OPENGL) {
|
version(USE_OPENGL) {
|
||||||
if (_enableOpengl)
|
if (_enableOpengl)
|
||||||
windowFlags |= SDL_WINDOW_OPENGL;
|
windowFlags |= SDL_WINDOW_OPENGL;
|
||||||
|
if (!_glSupport)
|
||||||
|
_glSupport = new GLSupport();
|
||||||
}
|
}
|
||||||
_win = SDL_CreateWindow(toUTF8(_caption).toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
_win = SDL_CreateWindow(toUTF8(_caption).toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
700, 500,
|
700, 500,
|
||||||
|
@ -127,7 +129,7 @@ class SDLWindow : Window {
|
||||||
} else if (!_gl3Reloaded) {
|
} else if (!_gl3Reloaded) {
|
||||||
DerelictGL3.reload();
|
DerelictGL3.reload();
|
||||||
_gl3Reloaded = true;
|
_gl3Reloaded = true;
|
||||||
if (!initShaders())
|
if (!glSupport.valid && !glSupport.initShaders())
|
||||||
_enableOpengl = false;
|
_enableOpengl = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Win32ColorDrawBuf : ColorDrawBufBase {
|
||||||
/// create resized copy of ColorDrawBuf
|
/// create resized copy of ColorDrawBuf
|
||||||
this(ColorDrawBuf v, int dx, int dy) {
|
this(ColorDrawBuf v, int dx, int dy) {
|
||||||
this(dx, dy);
|
this(dx, dy);
|
||||||
|
resetClipping();
|
||||||
fill(0xFFFFFFFF);
|
fill(0xFFFFFFFF);
|
||||||
if (_dx == dx && _dy == dy)
|
if (_dx == dx && _dy == dy)
|
||||||
drawImage(0, 0, v);
|
drawImage(0, 0, v);
|
||||||
|
@ -87,7 +88,7 @@ class Win32ColorDrawBuf : ColorDrawBufBase {
|
||||||
//return CreateBitmap(_dx, _dy, 1, 1, buf.ptr);
|
//return CreateBitmap(_dx, _dy, 1, 1, buf.ptr);
|
||||||
}
|
}
|
||||||
/// destroy object, but leave bitmap as is
|
/// destroy object, but leave bitmap as is
|
||||||
HBITMAP destoryLeavingBitmap() {
|
HBITMAP destroyLeavingBitmap() {
|
||||||
HBITMAP res = _drawbmp;
|
HBITMAP res = _drawbmp;
|
||||||
_drawbmp = null;
|
_drawbmp = null;
|
||||||
destroy(this);
|
destroy(this);
|
||||||
|
|
|
@ -154,10 +154,12 @@ version (USE_OPENGL) {
|
||||||
|
|
||||||
class Win32Window : Window {
|
class Win32Window : Window {
|
||||||
Win32Platform _platform;
|
Win32Platform _platform;
|
||||||
|
|
||||||
HWND _hwnd;
|
HWND _hwnd;
|
||||||
version (USE_OPENGL) {
|
version (USE_OPENGL) {
|
||||||
HGLRC _hGLRC; // opengl context
|
HGLRC _hGLRC; // opengl context
|
||||||
HPALETTE _hPalette;
|
HPALETTE _hPalette;
|
||||||
|
GLSupport _gl;
|
||||||
}
|
}
|
||||||
dstring _caption;
|
dstring _caption;
|
||||||
Win32ColorDrawBuf _drawbuf;
|
Win32ColorDrawBuf _drawbuf;
|
||||||
|
@ -167,6 +169,9 @@ class Win32Window : Window {
|
||||||
Win32Window w32parent = cast(Win32Window)parent;
|
Win32Window w32parent = cast(Win32Window)parent;
|
||||||
HWND parenthwnd = w32parent ? w32parent._hwnd : null;
|
HWND parenthwnd = w32parent ? w32parent._hwnd : null;
|
||||||
_platform = platform;
|
_platform = platform;
|
||||||
|
version (USE_OPENGL) {
|
||||||
|
_gl = new GLSupport();
|
||||||
|
}
|
||||||
_caption = windowCaption;
|
_caption = windowCaption;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
uint ws = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
uint ws = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||||
|
@ -199,7 +204,9 @@ class Win32Window : Window {
|
||||||
_hPalette = setupPalette(hDC);
|
_hPalette = setupPalette(hDC);
|
||||||
_hGLRC = wglCreateContext(hDC);
|
_hGLRC = wglCreateContext(hDC);
|
||||||
if (_hGLRC) {
|
if (_hGLRC) {
|
||||||
|
|
||||||
wglMakeCurrent(hDC, _hGLRC);
|
wglMakeCurrent(hDC, _hGLRC);
|
||||||
|
_glSupport = _gl;
|
||||||
|
|
||||||
if (!DERELICT_GL3_RELOADED) {
|
if (!DERELICT_GL3_RELOADED) {
|
||||||
// run this code only once
|
// run this code only once
|
||||||
|
@ -208,7 +215,7 @@ class Win32Window : Window {
|
||||||
import derelict.opengl3.gl3;
|
import derelict.opengl3.gl3;
|
||||||
DerelictGL3.reload();
|
DerelictGL3.reload();
|
||||||
// successful
|
// successful
|
||||||
if (initShaders()) {
|
if (glSupport.initShaders()) {
|
||||||
setOpenglEnabled();
|
setOpenglEnabled();
|
||||||
useOpengl = true;
|
useOpengl = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,7 +225,7 @@ class Win32Window : Window {
|
||||||
Log.e("Derelict exception", e);
|
Log.e("Derelict exception", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (initShaders()) {
|
if (glSupport.initShaders()) {
|
||||||
setOpenglEnabled();
|
setOpenglEnabled();
|
||||||
useOpengl = true;
|
useOpengl = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -252,6 +259,7 @@ class Win32Window : Window {
|
||||||
//scope(exit) EndPaint(_hwnd, &ps);
|
//scope(exit) EndPaint(_hwnd, &ps);
|
||||||
HDC hdc = GetDC(_hwnd);
|
HDC hdc = GetDC(_hwnd);
|
||||||
wglMakeCurrent(hdc, _hGLRC);
|
wglMakeCurrent(hdc, _hGLRC);
|
||||||
|
_glSupport = _gl;
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glViewport(0, 0, _dx, _dy);
|
glViewport(0, 0, _dx, _dy);
|
||||||
float a = 1.0f;
|
float a = 1.0f;
|
||||||
|
@ -288,7 +296,10 @@ class Win32Window : Window {
|
||||||
version (USE_OPENGL) {
|
version (USE_OPENGL) {
|
||||||
import derelict.opengl3.wgl;
|
import derelict.opengl3.wgl;
|
||||||
if (_hGLRC) {
|
if (_hGLRC) {
|
||||||
uninitShaders();
|
glSupport.uninitShaders();
|
||||||
|
destroy(_glSupport);
|
||||||
|
_glSupport = null;
|
||||||
|
_gl = null;
|
||||||
wglMakeCurrent (null, null) ;
|
wglMakeCurrent (null, null) ;
|
||||||
wglDeleteContext(_hGLRC);
|
wglDeleteContext(_hGLRC);
|
||||||
_hGLRC = null;
|
_hGLRC = null;
|
||||||
|
@ -440,7 +451,7 @@ class Win32Window : Window {
|
||||||
resizedicon.invertAlpha();
|
resizedicon.invertAlpha();
|
||||||
ICONINFO ii;
|
ICONINFO ii;
|
||||||
HBITMAP mask = resizedicon.createTransparencyBitmap();
|
HBITMAP mask = resizedicon.createTransparencyBitmap();
|
||||||
HBITMAP color = resizedicon.destoryLeavingBitmap();
|
HBITMAP color = resizedicon.destroyLeavingBitmap();
|
||||||
ii.fIcon = TRUE;
|
ii.fIcon = TRUE;
|
||||||
ii.xHotspot = 0;
|
ii.xHotspot = 0;
|
||||||
ii.yHotspot = 0;
|
ii.yHotspot = 0;
|
||||||
|
@ -448,8 +459,8 @@ class Win32Window : Window {
|
||||||
ii.hbmColor = color;
|
ii.hbmColor = color;
|
||||||
_icon = CreateIconIndirect(&ii);
|
_icon = CreateIconIndirect(&ii);
|
||||||
if (_icon) {
|
if (_icon) {
|
||||||
SendMessage(_hwnd, WM_SETICON, ICON_SMALL, cast(int)_icon);
|
SendMessageW(_hwnd, WM_SETICON, ICON_SMALL, cast(LPARAM)_icon);
|
||||||
SendMessage(_hwnd, WM_SETICON, ICON_BIG, cast(int)_icon);
|
SendMessageW(_hwnd, WM_SETICON, ICON_BIG, cast(LPARAM)_icon);
|
||||||
} else {
|
} else {
|
||||||
Log.e("failed to create icon");
|
Log.e("failed to create icon");
|
||||||
}
|
}
|
||||||
|
@ -470,7 +481,7 @@ class Win32Window : Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPaint() {
|
void onPaint() {
|
||||||
Log.d("onPaint()");
|
debug(DebugRedraw) Log.d("onPaint()");
|
||||||
long paintStart = currentTimeMillis;
|
long paintStart = currentTimeMillis;
|
||||||
version (USE_OPENGL) {
|
version (USE_OPENGL) {
|
||||||
if (useOpengl && _hGLRC) {
|
if (useOpengl && _hGLRC) {
|
||||||
|
@ -482,7 +493,7 @@ class Win32Window : Window {
|
||||||
paintUsingGDI();
|
paintUsingGDI();
|
||||||
}
|
}
|
||||||
long paintEnd = currentTimeMillis;
|
long paintEnd = currentTimeMillis;
|
||||||
Log.d("WM_PAINT handling took ", paintEnd - paintStart, " ms");
|
debug(DebugRedraw) Log.d("WM_PAINT handling took ", paintEnd - paintStart, " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ButtonDetails _lbutton;
|
protected ButtonDetails _lbutton;
|
||||||
|
@ -951,12 +962,17 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (window !is null) {
|
if (window !is null) {
|
||||||
WINDOWPOS * pos = cast(WINDOWPOS*)lParam;
|
WINDOWPOS * pos = cast(WINDOWPOS*)lParam;
|
||||||
|
Log.d("WM_WINDOWPOSCHANGED: ", *pos);
|
||||||
GetClientRect(hwnd, &rect);
|
GetClientRect(hwnd, &rect);
|
||||||
|
//window.onResize(pos.cx, pos.cy);
|
||||||
|
//if (!(pos.flags & 0x8000)) { //SWP_NOACTIVATE)) {
|
||||||
|
//if (pos.x > -30000) {
|
||||||
int dx = rect.right - rect.left;
|
int dx = rect.right - rect.left;
|
||||||
int dy = rect.bottom - rect.top;
|
int dy = rect.bottom - rect.top;
|
||||||
//window.onResize(pos.cx, pos.cy);
|
|
||||||
window.onResize(dx, dy);
|
window.onResize(dx, dy);
|
||||||
InvalidateRect(hwnd, null, FALSE);
|
InvalidateRect(hwnd, null, FALSE);
|
||||||
|
//}
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -73,13 +73,24 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
||||||
onItemClickListener(this, index);
|
onItemClickListener(this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// change enabled state
|
||||||
|
override @property Widget enabled(bool flg) {
|
||||||
|
super.enabled(flg);
|
||||||
|
_button.enabled = flg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// return true if state has State.Enabled flag set
|
||||||
|
override @property bool enabled() { return super.enabled; }
|
||||||
|
|
||||||
override bool onClick(Widget source) {
|
override bool onClick(Widget source) {
|
||||||
|
if (enabled)
|
||||||
showPopup();
|
showPopup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageButton createButton() {
|
protected ImageButton createButton() {
|
||||||
ImageButton res = new ImageButton("COMBOBOX_BUTTON", "scrollbar_btn_down");
|
ImageButton res = new ImageButton("COMBOBOX_BUTTON", "scrollbar_btn_down");
|
||||||
|
res.styleId = STYLE_COMBO_BOX_BUTTON;
|
||||||
res.layoutWeight = 0;
|
res.layoutWeight = 0;
|
||||||
res.onClickListener = this;
|
res.onClickListener = this;
|
||||||
return res;
|
return res;
|
||||||
|
@ -99,7 +110,7 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
||||||
_popupList = createPopup();
|
_popupList = createPopup();
|
||||||
_popup = window.showPopup(_popupList, this, PopupAlign.Below | PopupAlign.FitAnchorSize);
|
_popup = window.showPopup(_popupList, this, PopupAlign.Below | PopupAlign.FitAnchorSize);
|
||||||
_popup.flags = PopupFlags.CloseOnClickOutside;
|
_popup.flags = PopupFlags.CloseOnClickOutside;
|
||||||
_popup.styleId = "POPUP_MENU";
|
_popup.styleId = STYLE_POPUP_MENU;
|
||||||
_popup.onPopupCloseListener = delegate (PopupWidget source) {
|
_popup.onPopupCloseListener = delegate (PopupWidget source) {
|
||||||
_popup = null;
|
_popup = null;
|
||||||
_popupList = null;
|
_popupList = null;
|
||||||
|
@ -121,6 +132,8 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
||||||
super(ID);
|
super(ID);
|
||||||
_adapter = adapter;
|
_adapter = adapter;
|
||||||
_ownAdapter = ownAdapter;
|
_ownAdapter = ownAdapter;
|
||||||
|
styleId = STYLE_COMBO_BOX;
|
||||||
|
trackHover = true;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +144,8 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
||||||
//_body.state = State.Parent;
|
//_body.state = State.Parent;
|
||||||
//focusable = true;
|
//focusable = true;
|
||||||
_button.focusable = false;
|
_button.focusable = false;
|
||||||
|
_body.focusable = false;
|
||||||
|
focusable = true;
|
||||||
//_body.focusable = true;
|
//_body.focusable = true;
|
||||||
addChild(_body);
|
addChild(_body);
|
||||||
addChild(_button);
|
addChild(_button);
|
||||||
|
@ -198,14 +213,13 @@ class ComboBox : ComboBoxBase {
|
||||||
_body.focusable = false;
|
_body.focusable = false;
|
||||||
_body.clickable = true;
|
_body.clickable = true;
|
||||||
focusable = true;
|
focusable = true;
|
||||||
//styleId = "COMBO_BOX";
|
|
||||||
clickable = true;
|
clickable = true;
|
||||||
onClickListener = this;
|
onClickListener = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected Widget createSelectedItemWidget() {
|
override protected Widget createSelectedItemWidget() {
|
||||||
TextWidget res = new TextWidget("COMBOBOX_BODY");
|
TextWidget res = new TextWidget("COMBO_BOX_BODY");
|
||||||
res.styleId = "COMBO_BOX";
|
res.styleId = STYLE_COMBO_BOX_BODY;
|
||||||
res.clickable = true;
|
res.clickable = true;
|
||||||
res.layoutWidth = FILL_PARENT;
|
res.layoutWidth = FILL_PARENT;
|
||||||
res.layoutHeight = WRAP_CONTENT;
|
res.layoutHeight = WRAP_CONTENT;
|
||||||
|
@ -264,8 +278,8 @@ class ComboEdit : ComboBox {
|
||||||
|
|
||||||
override void init() {
|
override void init() {
|
||||||
super.init();
|
super.init();
|
||||||
focusable = false;
|
//focusable = false;
|
||||||
_body.focusable = true;
|
//_body.focusable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ private import std.conv : to;
|
||||||
/// vertical spacer to fill empty space in vertical layouts
|
/// vertical spacer to fill empty space in vertical layouts
|
||||||
class VSpacer : Widget {
|
class VSpacer : Widget {
|
||||||
this() {
|
this() {
|
||||||
styleId = "VSPACER";
|
styleId = STYLE_VSPACER;
|
||||||
}
|
}
|
||||||
//override void measure(int parentWidth, int parentHeight) {
|
//override void measure(int parentWidth, int parentHeight) {
|
||||||
// measuredContent(parentWidth, parentHeight, 8, 8);
|
// measuredContent(parentWidth, parentHeight, 8, 8);
|
||||||
|
@ -46,7 +46,7 @@ class VSpacer : Widget {
|
||||||
/// horizontal spacer to fill empty space in horizontal layouts
|
/// horizontal spacer to fill empty space in horizontal layouts
|
||||||
class HSpacer : Widget {
|
class HSpacer : Widget {
|
||||||
this() {
|
this() {
|
||||||
styleId = "HSPACER";
|
styleId = STYLE_HSPACER;
|
||||||
}
|
}
|
||||||
//override void measure(int parentWidth, int parentHeight) {
|
//override void measure(int parentWidth, int parentHeight) {
|
||||||
// measuredContent(parentWidth, parentHeight, 8, 8);
|
// measuredContent(parentWidth, parentHeight, 8, 8);
|
||||||
|
@ -57,12 +57,12 @@ class HSpacer : Widget {
|
||||||
class TextWidget : Widget {
|
class TextWidget : Widget {
|
||||||
this(string ID = null, string textResourceId = null) {
|
this(string ID = null, string textResourceId = null) {
|
||||||
super(ID);
|
super(ID);
|
||||||
styleId = "TEXT";
|
styleId = STYLE_TEXT;
|
||||||
_text = textResourceId;
|
_text = textResourceId;
|
||||||
}
|
}
|
||||||
this(string ID, dstring rawText) {
|
this(string ID, dstring rawText) {
|
||||||
super(ID);
|
super(ID);
|
||||||
styleId = "TEXT";
|
styleId = STYLE_TEXT;
|
||||||
_text = rawText;
|
_text = rawText;
|
||||||
}
|
}
|
||||||
protected UIString _text;
|
protected UIString _text;
|
||||||
|
@ -199,7 +199,7 @@ class ImageButton : ImageWidget {
|
||||||
/// constructor by id and icon resource id
|
/// constructor by id and icon resource id
|
||||||
this(string ID = null, string drawableId = null) {
|
this(string ID = null, string drawableId = null) {
|
||||||
super(ID, drawableId);
|
super(ID, drawableId);
|
||||||
styleId = "BUTTON";
|
styleId = STYLE_BUTTON;
|
||||||
_drawableId = drawableId;
|
_drawableId = drawableId;
|
||||||
clickable = true;
|
clickable = true;
|
||||||
focusable = true;
|
focusable = true;
|
||||||
|
@ -247,10 +247,11 @@ class ImageTextButton : HorizontalLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init(string drawableId, UIString caption) {
|
protected void init(string drawableId, UIString caption) {
|
||||||
styleId = "BUTTON";
|
styleId = STYLE_BUTTON;
|
||||||
_icon = new ImageWidget("icon", drawableId);
|
_icon = new ImageWidget("icon", drawableId);
|
||||||
|
_icon.styleId = STYLE_BUTTON_IMAGE;
|
||||||
_label = new TextWidget("label", caption);
|
_label = new TextWidget("label", caption);
|
||||||
_label.styleId = "BUTTON_LABEL";
|
_label.styleId = STYLE_BUTTON_LABEL;
|
||||||
_icon.state = State.Parent;
|
_icon.state = State.Parent;
|
||||||
_label.state = State.Parent;
|
_label.state = State.Parent;
|
||||||
addChild(_icon);
|
addChild(_icon);
|
||||||
|
@ -285,12 +286,17 @@ class ImageTextButton : HorizontalLayout {
|
||||||
class CheckBox : ImageTextButton {
|
class CheckBox : ImageTextButton {
|
||||||
this(string ID = null, string textResourceId = null) {
|
this(string ID = null, string textResourceId = null) {
|
||||||
super(ID, "btn_check", textResourceId);
|
super(ID, "btn_check", textResourceId);
|
||||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
|
||||||
checkable = true;
|
|
||||||
}
|
}
|
||||||
this(string ID, dstring labelText) {
|
this(string ID, dstring labelText) {
|
||||||
super(ID, "btn_check", labelText);
|
super(ID, "btn_check", labelText);
|
||||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
}
|
||||||
|
override protected void init(string drawableId, UIString caption) {
|
||||||
|
super.init(drawableId, caption);
|
||||||
|
styleId = STYLE_CHECKBOX;
|
||||||
|
if (_icon)
|
||||||
|
_icon.styleId = STYLE_CHECKBOX_IMAGE;
|
||||||
|
if (_label)
|
||||||
|
_label.styleId = STYLE_CHECKBOX_LABEL;
|
||||||
checkable = true;
|
checkable = true;
|
||||||
}
|
}
|
||||||
// called to process click and notify listeners
|
// called to process click and notify listeners
|
||||||
|
@ -304,12 +310,17 @@ class CheckBox : ImageTextButton {
|
||||||
class RadioButton : ImageTextButton {
|
class RadioButton : ImageTextButton {
|
||||||
this(string ID = null, string textResourceId = null) {
|
this(string ID = null, string textResourceId = null) {
|
||||||
super(ID, "btn_radio", textResourceId);
|
super(ID, "btn_radio", textResourceId);
|
||||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
|
||||||
checkable = true;
|
|
||||||
}
|
}
|
||||||
this(string ID, dstring labelText) {
|
this(string ID, dstring labelText) {
|
||||||
super(ID, "btn_radio", labelText);
|
super(ID, "btn_radio", labelText);
|
||||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
}
|
||||||
|
override protected void init(string drawableId, UIString caption) {
|
||||||
|
super.init(drawableId, caption);
|
||||||
|
styleId = STYLE_RADIOBUTTON;
|
||||||
|
if (_icon)
|
||||||
|
_icon.styleId = STYLE_RADIOBUTTON_IMAGE;
|
||||||
|
if (_label)
|
||||||
|
_label.styleId = STYLE_RADIOBUTTON_LABEL;
|
||||||
checkable = true;
|
checkable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +362,7 @@ class Button : Widget {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(UIString label) {
|
private void init(UIString label) {
|
||||||
styleId = "BUTTON";
|
styleId = STYLE_BUTTON;
|
||||||
_text = label;
|
_text = label;
|
||||||
clickable = true;
|
clickable = true;
|
||||||
focusable = true;
|
focusable = true;
|
||||||
|
@ -397,7 +408,7 @@ class Button : Widget {
|
||||||
FontRef font = font();
|
FontRef font = font();
|
||||||
Point sz = font.textSize(text);
|
Point sz = font.textSize(text);
|
||||||
applyAlign(rc, sz);
|
applyAlign(rc, sz);
|
||||||
font.drawText(buf, rc.left, rc.top, text, textColor);
|
font.drawText(buf, rc.left, rc.top, text, textColor, 4, 0, textFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -497,7 +508,7 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
||||||
class PageScrollButton : Widget {
|
class PageScrollButton : Widget {
|
||||||
this(string ID) {
|
this(string ID) {
|
||||||
super(ID);
|
super(ID);
|
||||||
styleId = "PAGE_SCROLL";
|
styleId = STYLE_PAGE_SCROLL;
|
||||||
trackHover = true;
|
trackHover = true;
|
||||||
clickable = true;
|
clickable = true;
|
||||||
}
|
}
|
||||||
|
@ -511,7 +522,7 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
||||||
|
|
||||||
this(string resourceId) {
|
this(string resourceId) {
|
||||||
super("SLIDER", resourceId);
|
super("SLIDER", resourceId);
|
||||||
styleId = "BUTTON_NOMARGINS";
|
styleId = STYLE_BUTTON_NOMARGINS;
|
||||||
trackHover = true;
|
trackHover = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,14 +682,14 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
||||||
/// create with ID parameter
|
/// create with ID parameter
|
||||||
this(string ID, Orientation orient = Orientation.Vertical) {
|
this(string ID, Orientation orient = Orientation.Vertical) {
|
||||||
super(ID);
|
super(ID);
|
||||||
styleId = "SCROLLBAR";
|
styleId = STYLE_SCROLLBAR;
|
||||||
_orientation = orient;
|
_orientation = orient;
|
||||||
_btnBack = new ImageButton("BACK", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_UP : ATTR_SCROLLBAR_BUTTON_LEFT));
|
_btnBack = new ImageButton("BACK", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_UP : ATTR_SCROLLBAR_BUTTON_LEFT));
|
||||||
_btnForward = new ImageButton("FORWARD", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_DOWN : ATTR_SCROLLBAR_BUTTON_RIGHT));
|
_btnForward = new ImageButton("FORWARD", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_DOWN : ATTR_SCROLLBAR_BUTTON_RIGHT));
|
||||||
_pageUp = new PageScrollButton("PAGE_UP");
|
_pageUp = new PageScrollButton("PAGE_UP");
|
||||||
_pageDown = new PageScrollButton("PAGE_DOWN");
|
_pageDown = new PageScrollButton("PAGE_DOWN");
|
||||||
_btnBack.styleId("SCROLLBAR_BUTTON");
|
_btnBack.styleId = STYLE_SCROLLBAR_BUTTON;
|
||||||
_btnForward.styleId("SCROLLBAR_BUTTON");
|
_btnForward.styleId = STYLE_SCROLLBAR_BUTTON;
|
||||||
_indicator = new SliderButton(style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL));
|
_indicator = new SliderButton(style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL));
|
||||||
addChild(_btnBack);
|
addChild(_btnBack);
|
||||||
addChild(_btnForward);
|
addChild(_btnForward);
|
||||||
|
|
|
@ -926,6 +926,13 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns true if widget is focusable and visible and enabled
|
||||||
|
override @property bool canFocus() {
|
||||||
|
// allow to focus even if not enabled
|
||||||
|
return focusable && visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// override to change popup menu items state
|
/// override to change popup menu items state
|
||||||
override bool isActionEnabled(const Action action) {
|
override bool isActionEnabled(const Action action) {
|
||||||
switch (action.id) {
|
switch (action.id) {
|
||||||
|
@ -1727,7 +1734,7 @@ class EditLine : EditWidgetBase {
|
||||||
_content = new EditableContent(false);
|
_content = new EditableContent(false);
|
||||||
_content.contentChangeListeners = this;
|
_content.contentChangeListeners = this;
|
||||||
wantTabs = false;
|
wantTabs = false;
|
||||||
styleId = "EDIT_LINE";
|
styleId = STYLE_EDIT_LINE;
|
||||||
text = initialContent;
|
text = initialContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1905,7 +1912,7 @@ class EditBox : EditWidgetBase {
|
||||||
super(ID, hscrollbarMode, vscrollbarMode);
|
super(ID, hscrollbarMode, vscrollbarMode);
|
||||||
_content = new EditableContent(true); // multiline
|
_content = new EditableContent(true); // multiline
|
||||||
_content.contentChangeListeners = this;
|
_content.contentChangeListeners = this;
|
||||||
styleId = "EDIT_BOX";
|
styleId = STYLE_EDIT_BOX;
|
||||||
text = initialContent;
|
text = initialContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1170,7 +1170,7 @@ class StringGridWidget : StringGridWidgetBase {
|
||||||
/// create with ID parameter
|
/// create with ID parameter
|
||||||
this(string ID) {
|
this(string ID) {
|
||||||
super(ID);
|
super(ID);
|
||||||
styleId = "EDIT_BOX";
|
styleId = STYLE_EDIT_BOX;
|
||||||
}
|
}
|
||||||
/// get cell text
|
/// get cell text
|
||||||
override dstring cellText(int col, int row) {
|
override dstring cellText(int col, int row) {
|
||||||
|
|
|
@ -174,15 +174,20 @@ class LayoutItems {
|
||||||
contentSecondarySize = maxItem;
|
contentSecondarySize = maxItem;
|
||||||
else
|
else
|
||||||
contentSecondarySize = rc.width;
|
contentSecondarySize = rc.width;
|
||||||
if (_layoutHeight == FILL_PARENT || totalSize > rc.height)
|
if (_layoutHeight == FILL_PARENT && totalSize < rc.height && resizableSize > 0) {
|
||||||
delta = rc.height - totalSize; // total space to add to fit
|
delta = rc.height - totalSize; // total space to add to fit
|
||||||
|
} else if (totalSize > rc.height) {
|
||||||
|
delta = rc.height - totalSize; // total space to reduce to fit
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_layoutHeight == WRAP_CONTENT && maxItem < rc.height)
|
if (_layoutHeight == WRAP_CONTENT && maxItem < rc.height)
|
||||||
contentSecondarySize = maxItem;
|
contentSecondarySize = maxItem;
|
||||||
else
|
else
|
||||||
contentSecondarySize = rc.height;
|
contentSecondarySize = rc.height;
|
||||||
if (_layoutWidth == FILL_PARENT || totalSize > rc.width)
|
if (_layoutWidth == FILL_PARENT && totalSize < rc.width && resizableSize > 0)
|
||||||
delta = rc.width - totalSize; // total space to add to fit
|
delta = rc.width - totalSize; // total space to add to fit
|
||||||
|
else if (totalSize > rc.width)
|
||||||
|
delta = rc.width - totalSize; // total space to reduce to fit
|
||||||
}
|
}
|
||||||
// calculate resize options and scale
|
// calculate resize options and scale
|
||||||
bool needForceResize = false;
|
bool needForceResize = false;
|
||||||
|
@ -194,7 +199,7 @@ class LayoutItems {
|
||||||
// need resize of some children
|
// need resize of some children
|
||||||
needResize = true;
|
needResize = true;
|
||||||
// resize all if need to shrink or only resizable are too small to correct delta
|
// resize all if need to shrink or only resizable are too small to correct delta
|
||||||
needForceResize = delta < 0 || resizableWeight == 0; // || resizableSize * 2 / 3 < delta; // do we need resize non-FILL_PARENT items?
|
needForceResize = /*delta < 0 || */ resizableWeight == 0; // || resizableSize * 2 / 3 < delta; // do we need resize non-FILL_PARENT items?
|
||||||
// calculate scale factor: weight / delta * 10000
|
// calculate scale factor: weight / delta * 10000
|
||||||
if (needForceResize && nonresizableSize + resizableSize > 0)
|
if (needForceResize && nonresizableSize + resizableSize > 0)
|
||||||
scaleFactor = 10000 * delta / (nonresizableSize + resizableSize);
|
scaleFactor = 10000 * delta / (nonresizableSize + resizableSize);
|
||||||
|
@ -467,7 +472,7 @@ class ResizerWidget : Widget {
|
||||||
|
|
||||||
|
|
||||||
/// Arranges items either vertically or horizontally
|
/// Arranges items either vertically or horizontally
|
||||||
class LinearLayout : WidgetGroup {
|
class LinearLayout : WidgetGroupDefaultDrawing {
|
||||||
protected Orientation _orientation = Orientation.Vertical;
|
protected Orientation _orientation = Orientation.Vertical;
|
||||||
/// returns linear layout orientation (Vertical, Horizontal)
|
/// returns linear layout orientation (Vertical, Horizontal)
|
||||||
@property Orientation orientation() { return _orientation; }
|
@property Orientation orientation() { return _orientation; }
|
||||||
|
@ -514,22 +519,6 @@ class LinearLayout : WidgetGroup {
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
_layoutItems.layout(rc);
|
_layoutItems.layout(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);
|
|
||||||
applyPadding(rc);
|
|
||||||
auto saver = ClipRectSaver(buf, rc);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +549,7 @@ class HorizontalLayout : LinearLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// place all children into same place (usually, only one child should be visible at a time)
|
/// place all children into same place (usually, only one child should be visible at a time)
|
||||||
class FrameLayout : WidgetGroup {
|
class FrameLayout : WidgetGroupDefaultDrawing {
|
||||||
/// empty parameter list constructor - for usage by factory
|
/// empty parameter list constructor - for usage by factory
|
||||||
this() {
|
this() {
|
||||||
this(null);
|
this(null);
|
||||||
|
@ -612,23 +601,6 @@ class FrameLayout : WidgetGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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);
|
|
||||||
applyPadding(rc);
|
|
||||||
auto saver = ClipRectSaver(buf, rc);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// make one of children (with specified ID) visible, for the rest, set visibility to otherChildrenVisibility
|
/// make one of children (with specified ID) visible, for the rest, set visibility to otherChildrenVisibility
|
||||||
bool showChild(string ID, Visibility otherChildrenVisibility = Visibility.Invisible, bool updateFocus = false) {
|
bool showChild(string ID, Visibility otherChildrenVisibility = Visibility.Invisible, bool updateFocus = false) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -650,7 +622,7 @@ class FrameLayout : WidgetGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// layout children as table with rows and columns
|
/// layout children as table with rows and columns
|
||||||
class TableLayout : WidgetGroup {
|
class TableLayout : WidgetGroupDefaultDrawing {
|
||||||
|
|
||||||
this(string ID = null) {
|
this(string ID = null) {
|
||||||
super(ID);
|
super(ID);
|
||||||
|
@ -840,21 +812,4 @@ class TableLayout : WidgetGroup {
|
||||||
_cells.layout(rc);
|
_cells.layout(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);
|
|
||||||
applyPadding(rc);
|
|
||||||
auto saver = ClipRectSaver(buf, rc);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ class StringListAdapter : ListAdapter {
|
||||||
updateStatesLength();
|
updateStatesLength();
|
||||||
if (_widget is null) {
|
if (_widget is null) {
|
||||||
_widget = new TextWidget("LIST_ITEM");
|
_widget = new TextWidget("LIST_ITEM");
|
||||||
_widget.styleId = "LIST_ITEM";
|
_widget.styleId = STYLE_LIST_ITEM;
|
||||||
} else {
|
} else {
|
||||||
if (index == _lastItemIndex)
|
if (index == _lastItemIndex)
|
||||||
return _widget;
|
return _widget;
|
||||||
|
|
|
@ -206,7 +206,7 @@ class MenuItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// widget to draw menu item
|
/// widget to draw menu item
|
||||||
class MenuItemWidget : WidgetGroup {
|
class MenuItemWidget : WidgetGroupDefaultDrawing {
|
||||||
protected bool _mainMenu;
|
protected bool _mainMenu;
|
||||||
protected MenuItem _item;
|
protected MenuItem _item;
|
||||||
protected ImageWidget _icon;
|
protected ImageWidget _icon;
|
||||||
|
@ -298,29 +298,11 @@ class MenuItemWidget : WidgetGroup {
|
||||||
resetState(State.Checked);
|
resetState(State.Checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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);
|
|
||||||
applyPadding(rc);
|
|
||||||
updateState();
|
|
||||||
auto saver = ClipRectSaver(buf, rc, alpha);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this(MenuItem item, bool mainMenu) {
|
this(MenuItem item, bool mainMenu) {
|
||||||
id="menuitem";
|
id="menuitem";
|
||||||
_mainMenu = mainMenu;
|
_mainMenu = mainMenu;
|
||||||
_item = item;
|
_item = item;
|
||||||
styleId = "MENU_ITEM";
|
styleId = STYLE_MENU_ITEM;
|
||||||
updateState();
|
updateState();
|
||||||
string iconId = _item.action.iconId;
|
string iconId = _item.action.iconId;
|
||||||
if (_item.type == MenuItemType.Check)
|
if (_item.type == MenuItemType.Check)
|
||||||
|
@ -330,7 +312,7 @@ class MenuItemWidget : WidgetGroup {
|
||||||
// icon
|
// icon
|
||||||
if (_item.action && iconId.length) {
|
if (_item.action && iconId.length) {
|
||||||
_icon = new ImageWidget("MENU_ICON", iconId);
|
_icon = new ImageWidget("MENU_ICON", iconId);
|
||||||
_icon.styleId = "MENU_ICON";
|
_icon.styleId = STYLE_MENU_ICON;
|
||||||
_icon.state = State.Parent;
|
_icon.state = State.Parent;
|
||||||
addChild(_icon);
|
addChild(_icon);
|
||||||
}
|
}
|
||||||
|
@ -352,7 +334,7 @@ class MenuItemWidget : WidgetGroup {
|
||||||
}
|
}
|
||||||
if (acc !is null) {
|
if (acc !is null) {
|
||||||
_accel = new TextWidget("MENU_ACCEL");
|
_accel = new TextWidget("MENU_ACCEL");
|
||||||
_accel.styleId = "MENU_ACCEL";
|
_accel.styleId = STYLE_MENU_ACCEL;
|
||||||
_accel.text = acc;
|
_accel.text = acc;
|
||||||
_accel.state = State.Parent;
|
_accel.state = State.Parent;
|
||||||
if (_item.isSubmenu && !mainMenu)
|
if (_item.isSubmenu && !mainMenu)
|
||||||
|
@ -382,13 +364,13 @@ class MenuWidgetBase : ListWidget {
|
||||||
_item = item;
|
_item = item;
|
||||||
this.orientation = orientation;
|
this.orientation = orientation;
|
||||||
id = "popup_menu";
|
id = "popup_menu";
|
||||||
styleId = "POPUP_MENU";
|
styleId = STYLE_POPUP_MENU;
|
||||||
WidgetListAdapter adapter = new WidgetListAdapter();
|
WidgetListAdapter adapter = new WidgetListAdapter();
|
||||||
for (int i=0; i < _item.subitemCount; i++) {
|
for (int i=0; i < _item.subitemCount; i++) {
|
||||||
MenuItem subitem = _item.subitem(i);
|
MenuItem subitem = _item.subitem(i);
|
||||||
MenuItemWidget widget = new MenuItemWidget(subitem, orientation == Orientation.Horizontal);
|
MenuItemWidget widget = new MenuItemWidget(subitem, orientation == Orientation.Horizontal);
|
||||||
if (orientation == Orientation.Horizontal)
|
if (orientation == Orientation.Horizontal)
|
||||||
widget.styleId = "MAIN_MENU_ITEM";
|
widget.styleId = STYLE_MAIN_MENU_ITEM;
|
||||||
widget.parent = this;
|
widget.parent = this;
|
||||||
adapter.widgets.add(widget);
|
adapter.widgets.add(widget);
|
||||||
}
|
}
|
||||||
|
@ -650,7 +632,7 @@ class MainMenu : MenuWidgetBase {
|
||||||
this(MenuItem item) {
|
this(MenuItem item) {
|
||||||
super(null, item, Orientation.Horizontal);
|
super(null, item, Orientation.Horizontal);
|
||||||
id = "MAIN_MENU";
|
id = "MAIN_MENU";
|
||||||
styleId = "MAIN_MENU";
|
styleId = STYLE_MAIN_MENU;
|
||||||
_clickOnButtonDown = true;
|
_clickOnButtonDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,7 +781,7 @@ class PopupMenu : MenuWidgetBase {
|
||||||
this(MenuItem item, MenuWidgetBase parentMenu = null) {
|
this(MenuItem item, MenuWidgetBase parentMenu = null) {
|
||||||
super(parentMenu, item, Orientation.Vertical);
|
super(parentMenu, item, Orientation.Vertical);
|
||||||
id = "POPUP_MENU";
|
id = "POPUP_MENU";
|
||||||
styleId = "POPUP_MENU";
|
styleId = STYLE_POPUP_MENU;
|
||||||
selectOnHover = true;
|
selectOnHover = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,11 +217,19 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
|
||||||
pwidth -= m.left + m.right + p.left + p.right;
|
pwidth -= m.left + m.right + p.left + p.right;
|
||||||
if (parentHeight != SIZE_UNSPECIFIED)
|
if (parentHeight != SIZE_UNSPECIFIED)
|
||||||
pheight -= m.top + m.bottom + p.top + p.bottom;
|
pheight -= m.top + m.bottom + p.top + p.bottom;
|
||||||
if (_hscrollbar)
|
if (_hscrollbar) {
|
||||||
_hscrollbar.measure(pwidth, pheight);
|
_hscrollbar.measure(pwidth, pheight);
|
||||||
if (_vscrollbar)
|
}
|
||||||
|
if (_vscrollbar) {
|
||||||
_vscrollbar.measure(pwidth, pheight);
|
_vscrollbar.measure(pwidth, pheight);
|
||||||
|
}
|
||||||
Point sz = fullContentSize();
|
Point sz = fullContentSize();
|
||||||
|
if (_hscrollbar) {
|
||||||
|
sz.y += _hscrollbar.measuredHeight;
|
||||||
|
}
|
||||||
|
if (_vscrollbar) {
|
||||||
|
sz.x += _vscrollbar.measuredWidth;
|
||||||
|
}
|
||||||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,9 +300,9 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
|
||||||
If size of content widget exceeds available space, allows to scroll it.
|
If size of content widget exceeds available space, allows to scroll it.
|
||||||
*/
|
*/
|
||||||
class ScrollWidget : ScrollWidgetBase {
|
class ScrollWidget : ScrollWidgetBase {
|
||||||
protected WidgetGroup _contentWidget;
|
protected Widget _contentWidget;
|
||||||
@property WidgetGroup contentWidget() { return _contentWidget; }
|
@property Widget contentWidget() { return _contentWidget; }
|
||||||
@property ScrollWidget contentWidget(WidgetGroup newContent) {
|
@property ScrollWidget contentWidget(Widget newContent) {
|
||||||
if (_contentWidget) {
|
if (_contentWidget) {
|
||||||
removeChild(childIndex(_contentWidget));
|
removeChild(childIndex(_contentWidget));
|
||||||
destroy(_contentWidget);
|
destroy(_contentWidget);
|
||||||
|
|
|
@ -25,14 +25,110 @@ private import std.string;
|
||||||
private import std.algorithm;
|
private import std.algorithm;
|
||||||
|
|
||||||
import dlangui.core.types;
|
import dlangui.core.types;
|
||||||
|
import dlangui.graphics.colors;
|
||||||
import dlangui.graphics.fonts;
|
import dlangui.graphics.fonts;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import dlangui.graphics.resources;
|
import dlangui.graphics.resources;
|
||||||
|
|
||||||
|
// Standard style constants
|
||||||
|
// Themes should define all of these styles in order to support all controls
|
||||||
|
/// standard style id for TextWidget
|
||||||
|
immutable string STYLE_TEXT = "TEXT";
|
||||||
|
/// standard style id for Button
|
||||||
|
immutable string STYLE_BUTTON = "BUTTON";
|
||||||
|
/// standard style id for Button label
|
||||||
|
immutable string STYLE_BUTTON_LABEL = "BUTTON_LABEL";
|
||||||
|
/// standard style id for Button image
|
||||||
|
immutable string STYLE_BUTTON_IMAGE = "BUTTON_IMAGE";
|
||||||
|
/// style id for transparent Button
|
||||||
|
immutable string STYLE_BUTTON_TRANSPARENT = "BUTTON_TRANSPARENT";
|
||||||
|
/// style id for Button w/o margins
|
||||||
|
immutable string STYLE_BUTTON_NOMARGINS = "BUTTON_NOMARGINS";
|
||||||
|
/// standard style id for CheckBox
|
||||||
|
immutable string STYLE_CHECKBOX = "CHECKBOX";
|
||||||
|
/// standard style id for CheckBox image
|
||||||
|
immutable string STYLE_CHECKBOX_IMAGE = "CHECKBOX_IMAGE";
|
||||||
|
/// standard style id for CheckBox label
|
||||||
|
immutable string STYLE_CHECKBOX_LABEL = "CHECKBOX_LABEL";
|
||||||
|
/// standard style id for RadioButton
|
||||||
|
immutable string STYLE_RADIOBUTTON = "RADIOBUTTON";
|
||||||
|
/// standard style id for RadioButton image
|
||||||
|
immutable string STYLE_RADIOBUTTON_IMAGE = "RADIOBUTTON_IMAGE";
|
||||||
|
/// standard style id for RadioButton label
|
||||||
|
immutable string STYLE_RADIOBUTTON_LABEL = "RADIOBUTTON_LABEL";
|
||||||
|
/// standard style id for HSpacer
|
||||||
|
immutable string STYLE_HSPACER = "HSPACER";
|
||||||
|
/// standard style id for VSpacer
|
||||||
|
immutable string STYLE_VSPACER = "VSPACER";
|
||||||
|
/// standard style id for ScrollBar
|
||||||
|
immutable string STYLE_SCROLLBAR = "SCROLLBAR";
|
||||||
|
/// standard style id for ScrollBar button
|
||||||
|
immutable string STYLE_SCROLLBAR_BUTTON = "SCROLLBAR_BUTTON";
|
||||||
|
/// standard style id for ScrollBar page control
|
||||||
|
immutable string STYLE_PAGE_SCROLL = "PAGE_SCROLL";
|
||||||
|
/// standard style id for Slider
|
||||||
|
immutable string STYLE_SLIDER = "SLIDER";
|
||||||
|
/// standard style id for TabWidget
|
||||||
|
immutable string STYLE_TAB_WIDGET = "TAB_WIDGET";
|
||||||
|
/// standard style id for Tab with Up alignment
|
||||||
|
immutable string STYLE_TAB_UP = "TAB_UP";
|
||||||
|
/// standard style id for button of Tab with Up alignment
|
||||||
|
immutable string STYLE_TAB_UP_BUTTON = "TAB_UP_BUTTON";
|
||||||
|
/// standard style id for button of Tab with Up alignment
|
||||||
|
immutable string STYLE_TAB_UP_BUTTON_TEXT = "TAB_UP_BUTTON_TEXT";
|
||||||
|
/// standard style id for TabHost
|
||||||
|
immutable string STYLE_TAB_HOST = "TAB_HOST";
|
||||||
|
/// standard style id for PopupMenu
|
||||||
|
immutable string STYLE_POPUP_MENU = "POPUP_MENU";
|
||||||
|
/// standard style id for menu item
|
||||||
|
immutable string STYLE_MENU_ITEM = "MENU_ITEM";
|
||||||
|
/// standard style id for menu item label
|
||||||
|
immutable string STYLE_MENU_LABEL = "MENU_LABEL";
|
||||||
|
/// standard style id for menu item icon
|
||||||
|
immutable string STYLE_MENU_ICON = "MENU_ICON";
|
||||||
|
/// standard style id for menu item accelerators label
|
||||||
|
immutable string STYLE_MENU_ACCEL = "MENU_ACCEL";
|
||||||
|
/// standard style id for main menu item
|
||||||
|
immutable string STYLE_MAIN_MENU_ITEM = "MAIN_MENU_ITEM";
|
||||||
|
/// standard style id for main menu item label
|
||||||
|
immutable string STYLE_MAIN_MENU_LABEL = "MAIN_MENU_LABEL";
|
||||||
|
/// standard style id for main menu
|
||||||
|
immutable string STYLE_MAIN_MENU = "MAIN_MENU";
|
||||||
|
/// standard style id for list items
|
||||||
|
immutable string STYLE_LIST_ITEM = "LIST_ITEM";
|
||||||
|
/// standard style id for EditLine
|
||||||
|
immutable string STYLE_EDIT_LINE = "EDIT_LINE";
|
||||||
|
/// standard style id for EditBox
|
||||||
|
immutable string STYLE_EDIT_BOX = "EDIT_BOX";
|
||||||
|
/// standard style id for background similar to transparent button
|
||||||
|
immutable string STYLE_TRANSPARENT_BUTTON_BACKGROUND = "TRANSPARENT_BUTTON_BACKGROUND";
|
||||||
|
/// standard style id for tree item
|
||||||
|
immutable string STYLE_TREE_ITEM = "TREE_ITEM";
|
||||||
|
/// standard style id for tree item label
|
||||||
|
immutable string STYLE_TREE_ITEM_LABEL = "TREE_ITEM_LABEL";
|
||||||
|
/// standard style id for tree item icon
|
||||||
|
immutable string STYLE_TREE_ITEM_ICON = "TREE_ITEM_ICON";
|
||||||
|
/// standard style id for tree item expand icon
|
||||||
|
immutable string STYLE_TREE_ITEM_EXPAND_ICON = "TREE_ITEM_EXPAND_ICON";
|
||||||
|
/// standard style id for combo box
|
||||||
|
immutable string STYLE_COMBO_BOX = "COMBO_BOX";
|
||||||
|
/// standard style id for combo box button
|
||||||
|
immutable string STYLE_COMBO_BOX_BUTTON = "COMBO_BOX_BUTTON";
|
||||||
|
/// standard style id for combo box body (current item)
|
||||||
|
immutable string STYLE_COMBO_BOX_BODY = "COMBO_BOX_BODY";
|
||||||
|
|
||||||
|
// Layout size constants
|
||||||
|
/// layout option, to occupy all available place
|
||||||
|
immutable int FILL_PARENT = int.max - 1;
|
||||||
|
/// layout option, for size based on content
|
||||||
|
immutable int WRAP_CONTENT = int.max - 2;
|
||||||
|
/// use as widget.layout() param to avoid applying of parent size
|
||||||
|
immutable int SIZE_UNSPECIFIED = int.max;
|
||||||
|
|
||||||
|
// Other style constants
|
||||||
|
|
||||||
|
/// unspecified align - to take parent's value instead
|
||||||
immutable ubyte ALIGN_UNSPECIFIED = 0;
|
immutable ubyte ALIGN_UNSPECIFIED = 0;
|
||||||
immutable uint COLOR_UNSPECIFIED = 0xFFDEADFF;
|
|
||||||
/// transparent color constant
|
|
||||||
immutable uint COLOR_TRANSPARENT = 0xFFFFFFFF;
|
|
||||||
/// unspecified font size constant - to take parent style property value
|
/// unspecified font size constant - to take parent style property value
|
||||||
immutable ushort FONT_SIZE_UNSPECIFIED = 0xFFFF;
|
immutable ushort FONT_SIZE_UNSPECIFIED = 0xFFFF;
|
||||||
/// unspecified font weight constant - to take parent style property value
|
/// unspecified font weight constant - to take parent style property value
|
||||||
|
@ -43,20 +139,19 @@ immutable ubyte FONT_STYLE_UNSPECIFIED = 0xFF;
|
||||||
immutable ubyte FONT_STYLE_NORMAL = 0x00;
|
immutable ubyte FONT_STYLE_NORMAL = 0x00;
|
||||||
/// italic font style constant
|
/// italic font style constant
|
||||||
immutable ubyte FONT_STYLE_ITALIC = 0x01;
|
immutable ubyte FONT_STYLE_ITALIC = 0x01;
|
||||||
/// use as widget.layout() param to avoid applying of parent size
|
|
||||||
immutable int SIZE_UNSPECIFIED = int.max;
|
|
||||||
/// use text flags from parent style
|
/// use text flags from parent style
|
||||||
immutable uint TEXT_FLAGS_UNSPECIFIED = uint.max;
|
immutable uint TEXT_FLAGS_UNSPECIFIED = uint.max;
|
||||||
/// use text flags from parent widget
|
/// use text flags from parent widget
|
||||||
immutable uint TEXT_FLAGS_USE_PARENT = uint.max - 1;
|
immutable uint TEXT_FLAGS_USE_PARENT = uint.max - 1;
|
||||||
|
|
||||||
/// layout option, to occupy all available place
|
|
||||||
immutable int FILL_PARENT = int.max - 1;
|
|
||||||
/// layout option, for size based on content
|
|
||||||
immutable int WRAP_CONTENT = int.max - 2;
|
|
||||||
/// to take layout weight from parent
|
/// to take layout weight from parent
|
||||||
immutable int WEIGHT_UNSPECIFIED = -1;
|
immutable int WEIGHT_UNSPECIFIED = -1;
|
||||||
|
|
||||||
|
/// returns true for WRAP_CONTENT, WRAP_CONTENT, SIZE_UNSPECIFIED
|
||||||
|
bool isSpecialSize(int sz) {
|
||||||
|
// don't forget to update if more special constants added
|
||||||
|
return sz >= WRAP_CONTENT;
|
||||||
|
}
|
||||||
|
|
||||||
/// Align option bit constants
|
/// Align option bit constants
|
||||||
enum Align : ubyte {
|
enum Align : ubyte {
|
||||||
/// alignment is not specified
|
/// alignment is not specified
|
||||||
|
@ -91,32 +186,6 @@ enum TextFlag : uint {
|
||||||
Underline = 8
|
Underline = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
/// custom drawable attribute container for styles
|
|
||||||
class DrawableAttribute {
|
|
||||||
protected string _id;
|
|
||||||
protected string _drawableId;
|
|
||||||
protected DrawableRef _drawable;
|
|
||||||
protected bool _initialized;
|
|
||||||
this(string id, string drawableId) {
|
|
||||||
_id = id;
|
|
||||||
_drawableId = drawableId;
|
|
||||||
}
|
|
||||||
@property string id() const { return _id; }
|
|
||||||
@property string drawableId() const { return _drawableId; }
|
|
||||||
@property void drawableId(string newDrawable) { _drawableId = newDrawable; clear(); }
|
|
||||||
@property ref DrawableRef drawable() const {
|
|
||||||
if (!_drawable.isNull)
|
|
||||||
return (cast(DrawableAttribute)this)._drawable;
|
|
||||||
(cast(DrawableAttribute)this)._drawable = drawableCache.get(_id);
|
|
||||||
(cast(DrawableAttribute)this)._initialized = true;
|
|
||||||
return (cast(DrawableAttribute)this)._drawable;
|
|
||||||
}
|
|
||||||
void clear() {
|
|
||||||
_drawable.clear();
|
|
||||||
_initialized = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// style properties
|
/// style properties
|
||||||
class Style {
|
class Style {
|
||||||
protected string _id;
|
protected string _id;
|
||||||
|
@ -146,10 +215,13 @@ class Style {
|
||||||
protected int _layoutHeight = SIZE_UNSPECIFIED;
|
protected int _layoutHeight = SIZE_UNSPECIFIED;
|
||||||
protected int _layoutWeight = WEIGHT_UNSPECIFIED;
|
protected int _layoutWeight = WEIGHT_UNSPECIFIED;
|
||||||
|
|
||||||
|
protected uint[] _focusRectColors;
|
||||||
|
|
||||||
protected Style[] _substates;
|
protected Style[] _substates;
|
||||||
protected Style[] _children;
|
protected Style[] _children;
|
||||||
|
|
||||||
protected DrawableAttribute[string] _customDrawables;
|
protected DrawableAttribute[string] _customDrawables;
|
||||||
|
protected uint[string] _customColors;
|
||||||
|
|
||||||
protected FontRef _font;
|
protected FontRef _font;
|
||||||
protected DrawableRef _backgroundDrawable;
|
protected DrawableRef _backgroundDrawable;
|
||||||
|
@ -226,6 +298,19 @@ class Style {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get custom color attribute
|
||||||
|
uint customColor(string id) {
|
||||||
|
if (id in _customColors)
|
||||||
|
return _customColors[id];
|
||||||
|
return parentStyle.customColor(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// sets custom color attribute for style
|
||||||
|
Style setCustomColor(string id, uint color) {
|
||||||
|
_customColors[id] = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===================================================
|
//===================================================
|
||||||
// font properties
|
// font properties
|
||||||
|
@ -532,6 +617,22 @@ class Style {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle (one for solid, two for vertical gradient) or null if no focus rect should be drawn for style
|
||||||
|
@property const(uint[]) focusRectColors() const {
|
||||||
|
if (_focusRectColors) {
|
||||||
|
if (_focusRectColors.length == 1 && _focusRectColors[0] == COLOR_UNSPECIFIED)
|
||||||
|
return null;
|
||||||
|
return cast(const)_focusRectColors;
|
||||||
|
}
|
||||||
|
return parentStyle.focusRectColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// sets colors to draw focus rectangle or null if no focus rect should be drawn for style
|
||||||
|
@property Style focusRectColors(uint[] colors) {
|
||||||
|
_focusRectColors = colors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
Style setPadding(int left, int top, int right, int bottom) {
|
Style setPadding(int left, int top, int right, int bottom) {
|
||||||
_padding.left = left;
|
_padding.left = left;
|
||||||
_padding.top = top;
|
_padding.top = top;
|
||||||
|
@ -616,7 +717,7 @@ class Theme : Style {
|
||||||
this(string id) {
|
this(string id) {
|
||||||
super(this, id);
|
super(this, id);
|
||||||
_parentStyle = null;
|
_parentStyle = null;
|
||||||
_backgroundColor = 0xFFFFFFFF; // transparent
|
_backgroundColor = COLOR_TRANSPARENT; // transparent
|
||||||
_textColor = 0x000000; // black
|
_textColor = 0x000000; // black
|
||||||
_align = Align.TopLeft;
|
_align = Align.TopLeft;
|
||||||
_fontSize = 14; // TODO: from settings or screen properties / DPI
|
_fontSize = 14; // TODO: from settings or screen properties / DPI
|
||||||
|
@ -677,18 +778,32 @@ class Theme : Style {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DrawableRef _emptyDrawable;
|
private DrawableRef _emptyDrawable;
|
||||||
@property override ref DrawableRef customDrawable(string id) const {
|
override ref DrawableRef customDrawable(string id) const {
|
||||||
if (id in _customDrawables)
|
if (id in _customDrawables)
|
||||||
return _customDrawables[id].drawable;
|
return _customDrawables[id].drawable;
|
||||||
return (cast(Theme)this)._emptyDrawable;
|
return (cast(Theme)this)._emptyDrawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property override string customDrawableId(string id) const {
|
override string customDrawableId(string id) const {
|
||||||
if (id in _customDrawables)
|
if (id in _customDrawables)
|
||||||
return _customDrawables[id].drawableId;
|
return _customDrawables[id].drawableId;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get custom color attribute - transparent by default
|
||||||
|
override uint customColor(string id) {
|
||||||
|
if (id in _customColors)
|
||||||
|
return _customColors[id];
|
||||||
|
return COLOR_TRANSPARENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle or null if no focus rect should be drawn for style
|
||||||
|
@property override const(uint[]) focusRectColors() const {
|
||||||
|
if (_focusRectColors)
|
||||||
|
return _focusRectColors;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// create new named style or get existing
|
/// create new named style or get existing
|
||||||
override Style createSubstyle(string id) {
|
override Style createSubstyle(string id) {
|
||||||
if (id !is null && id in _byId)
|
if (id !is null && id in _byId)
|
||||||
|
@ -745,14 +860,14 @@ Theme createDefaultTheme() {
|
||||||
}
|
}
|
||||||
//res.fontFace = "Arial Narrow";
|
//res.fontFace = "Arial Narrow";
|
||||||
res.fontSize = 15; // TODO: choose based on DPI
|
res.fontSize = 15; // TODO: choose based on DPI
|
||||||
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center).setMargins(5,5,5,5);
|
Style button = res.createSubstyle(STYLE_BUTTON).backgroundImageId("btn_background").alignment(Align.Center).setMargins(5,5,5,5);
|
||||||
res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
|
res.createSubstyle(STYLE_BUTTON_TRANSPARENT).backgroundImageId("btn_background_transparent").alignment(Align.Center);
|
||||||
res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
|
res.createSubstyle(STYLE_BUTTON_LABEL).layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
|
||||||
res.createSubstyle("BUTTON_ICON").alignment(Align.Center);
|
res.createSubstyle(STYLE_BUTTON_IMAGE).alignment(Align.Center);
|
||||||
res.createSubstyle("TEXT").setMargins(2,2,2,2).setPadding(1,1,1,1);
|
res.createSubstyle(STYLE_TEXT).setMargins(2,2,2,2).setPadding(1,1,1,1);
|
||||||
res.createSubstyle("HSPACER").layoutWidth(FILL_PARENT).minWidth(5).layoutWeight(100);
|
res.createSubstyle(STYLE_HSPACER).layoutWidth(FILL_PARENT).minWidth(5).layoutWeight(100);
|
||||||
res.createSubstyle("VSPACER").layoutHeight(FILL_PARENT).minHeight(5).layoutWeight(100);
|
res.createSubstyle(STYLE_VSPACER).layoutHeight(FILL_PARENT).minHeight(5).layoutWeight(100);
|
||||||
res.createSubstyle("BUTTON_NOMARGINS").backgroundImageId("btn_default_small").alignment(Align.Center); // .setMargins(5,5,5,5)
|
res.createSubstyle(STYLE_BUTTON_NOMARGINS).backgroundImageId("btn_background").alignment(Align.Center); // .setMargins(5,5,5,5)
|
||||||
//button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
//button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
||||||
//button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable");
|
//button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable");
|
||||||
//button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
//button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
||||||
|
@ -765,67 +880,67 @@ Theme createDefaultTheme() {
|
||||||
res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_VERTICAL, "scrollbar_indicator_vertical");
|
res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_VERTICAL, "scrollbar_indicator_vertical");
|
||||||
res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_HORIZONTAL, "scrollbar_indicator_horizontal");
|
res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_HORIZONTAL, "scrollbar_indicator_horizontal");
|
||||||
|
|
||||||
Style scrollbar = res.createSubstyle("SCROLLBAR");
|
Style scrollbar = res.createSubstyle(STYLE_SCROLLBAR);
|
||||||
scrollbar.backgroundColor(0xC0808080);
|
scrollbar.backgroundColor(0xC0808080);
|
||||||
Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
|
Style scrollbarButton = button.createSubstyle(STYLE_SCROLLBAR_BUTTON);
|
||||||
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
Style scrollbarSlider = res.createSubstyle(STYLE_SLIDER);
|
||||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
|
Style scrollbarPage = res.createSubstyle(STYLE_PAGE_SCROLL).backgroundColor(COLOR_TRANSPARENT);
|
||||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
||||||
scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
|
scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
|
||||||
|
|
||||||
Style tabUp = res.createSubstyle("TAB_UP");
|
Style tabUp = res.createSubstyle(STYLE_TAB_UP);
|
||||||
tabUp.backgroundImageId("tab_up_background");
|
tabUp.backgroundImageId("tab_up_background");
|
||||||
tabUp.layoutWidth(FILL_PARENT);
|
tabUp.layoutWidth(FILL_PARENT);
|
||||||
tabUp.createState(State.Selected, State.Selected).backgroundImageId("tab_up_backgrond_selected");
|
tabUp.createState(State.Selected, State.Selected).backgroundImageId("tab_up_backgrond_selected");
|
||||||
Style tabUpButtonText = res.createSubstyle("TAB_UP_BUTTON_TEXT");
|
Style tabUpButtonText = res.createSubstyle(STYLE_TAB_UP_BUTTON_TEXT);
|
||||||
tabUpButtonText.textColor(0x000000).fontSize(12).alignment(Align.Center);
|
tabUpButtonText.textColor(0x000000).fontSize(12).alignment(Align.Center);
|
||||||
tabUpButtonText.createState(State.Selected, State.Selected).textColor(0x000000);
|
tabUpButtonText.createState(State.Selected, State.Selected).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Selected|State.Focused, State.Selected|State.Focused).textColor(0x000000);
|
tabUpButtonText.createState(State.Selected|State.Focused, State.Selected|State.Focused).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Focused, State.Focused).textColor(0x000000);
|
tabUpButtonText.createState(State.Focused, State.Focused).textColor(0x000000);
|
||||||
tabUpButtonText.createState(State.Hovered, State.Hovered).textColor(0xFFE0E0);
|
tabUpButtonText.createState(State.Hovered, State.Hovered).textColor(0xFFE0E0);
|
||||||
Style tabUpButton = res.createSubstyle("TAB_UP_BUTTON");
|
Style tabUpButton = res.createSubstyle(STYLE_TAB_UP_BUTTON);
|
||||||
tabUpButton.backgroundImageId("tab_btn_up");
|
tabUpButton.backgroundImageId("tab_btn_up");
|
||||||
//tabUpButton.backgroundImageId("tab_btn_up_normal");
|
//tabUpButton.backgroundImageId("tab_btn_up_normal");
|
||||||
//tabUpButton.createState(State.Selected, State.Selected).backgroundImageId("tab_btn_up_selected");
|
//tabUpButton.createState(State.Selected, State.Selected).backgroundImageId("tab_btn_up_selected");
|
||||||
//tabUpButton.createState(State.Selected|State.Focused, State.Selected|State.Focused).backgroundImageId("tab_btn_up_focused_selected");
|
//tabUpButton.createState(State.Selected|State.Focused, State.Selected|State.Focused).backgroundImageId("tab_btn_up_focused_selected");
|
||||||
//tabUpButton.createState(State.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
|
//tabUpButton.createState(State.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
|
||||||
//tabUpButton.createState(State.Hovered, State.Hovered).backgroundImageId("tab_btn_up_hover");
|
//tabUpButton.createState(State.Hovered, State.Hovered).backgroundImageId("tab_btn_up_hover");
|
||||||
Style tabHost = res.createSubstyle("TAB_HOST");
|
Style tabHost = res.createSubstyle(STYLE_TAB_HOST);
|
||||||
tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
||||||
tabHost.backgroundColor(0xF0F0F0);
|
tabHost.backgroundColor(0xF0F0F0);
|
||||||
Style tabWidget = res.createSubstyle("TAB_WIDGET");
|
Style tabWidget = res.createSubstyle(STYLE_TAB_WIDGET);
|
||||||
tabWidget.setPadding(3,3,3,3).backgroundColor(0xEEEEEE);
|
tabWidget.setPadding(3,3,3,3).backgroundColor(0xEEEEEE);
|
||||||
//tabWidget.backgroundImageId("frame_blue");
|
//tabWidget.backgroundImageId("frame_blue");
|
||||||
//res.dumpStats();
|
//res.dumpStats();
|
||||||
|
|
||||||
Style mainMenu = res.createSubstyle("MAIN_MENU").backgroundColor(0xEFEFF2).layoutWidth(FILL_PARENT);
|
Style mainMenu = res.createSubstyle(STYLE_MAIN_MENU).backgroundColor(0xEFEFF2).layoutWidth(FILL_PARENT);
|
||||||
Style mainMenuItem = res.createSubstyle("MAIN_MENU_ITEM").setPadding(4,2,4,2).backgroundImageId("main_menu_item_background").textFlags(TEXT_FLAGS_USE_PARENT);
|
Style mainMenuItem = res.createSubstyle(STYLE_MAIN_MENU_ITEM).setPadding(4,2,4,2).backgroundImageId("main_menu_item_background").textFlags(TEXT_FLAGS_USE_PARENT);
|
||||||
Style menuItem = res.createSubstyle("MENU_ITEM").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
Style menuItem = res.createSubstyle(STYLE_MENU_ITEM).setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
||||||
menuItem.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
|
menuItem.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
|
||||||
menuItem.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
menuItem.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
||||||
menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
||||||
menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
|
menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
|
||||||
res.createSubstyle("MENU_ICON").setMargins(2,2,2,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).alpha(0xA0);
|
res.createSubstyle(STYLE_MENU_ICON).setMargins(2,2,2,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).alpha(0xA0);
|
||||||
res.createSubstyle("MENU_LABEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TextFlag.UnderlineHotKeys).createState(State.Enabled,0).textColor(0x80404040);
|
res.createSubstyle(STYLE_MENU_LABEL).setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TextFlag.UnderlineHotKeys).createState(State.Enabled,0).textColor(0x80404040);
|
||||||
res.createSubstyle("MAIN_MENU_LABEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TEXT_FLAGS_USE_PARENT).createState(State.Enabled,0).textColor(0x80404040);
|
res.createSubstyle(STYLE_MAIN_MENU_LABEL).setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).textFlags(TEXT_FLAGS_USE_PARENT).createState(State.Enabled,0).textColor(0x80404040);
|
||||||
res.createSubstyle("MENU_ACCEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).textColor(0x80404040);
|
res.createSubstyle(STYLE_MENU_ACCEL).setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).textColor(0x80404040);
|
||||||
|
|
||||||
Style transparentButtonBackground = res.createSubstyle("TRANSPARENT_BUTTON_BACKGROUND").backgroundImageId("transparent_button_background").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
Style transparentButtonBackground = res.createSubstyle(STYLE_TRANSPARENT_BUTTON_BACKGROUND).backgroundImageId("transparent_button_background").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
||||||
//transparentButtonBackground.createState(State.Focused, State.Focused).backgroundColor(0xC0C0C000);
|
//transparentButtonBackground.createState(State.Focused, State.Focused).backgroundColor(0xC0C0C000);
|
||||||
//transparentButtonBackground.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
//transparentButtonBackground.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
||||||
//transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
//transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
||||||
//transparentButtonBackground.createState(State.Hovered, State.Hovered).backgroundColor(0xD0FFFF00);
|
//transparentButtonBackground.createState(State.Hovered, State.Hovered).backgroundColor(0xD0FFFF00);
|
||||||
|
|
||||||
Style poopupMenu = res.createSubstyle("POPUP_MENU").backgroundImageId("popup_menu_background_normal");
|
Style poopupMenu = res.createSubstyle(STYLE_POPUP_MENU).backgroundImageId("popup_menu_background_normal");
|
||||||
|
|
||||||
Style listItem = res.createSubstyle("LIST_ITEM").backgroundImageId("list_item_background");
|
Style listItem = res.createSubstyle(STYLE_LIST_ITEM).backgroundImageId("list_item_background");
|
||||||
//listItem.createState(State.Selected, State.Selected).backgroundColor(0xC04040FF).textColor(0x000000);
|
//listItem.createState(State.Selected, State.Selected).backgroundColor(0xC04040FF).textColor(0x000000);
|
||||||
//listItem.createState(State.Enabled, 0).textColor(0x80000000); // half transparent text for disabled item
|
//listItem.createState(State.Enabled, 0).textColor(0x80000000); // half transparent text for disabled item
|
||||||
|
|
||||||
Style editLine = res.createSubstyle("EDIT_LINE").backgroundImageId("editbox_background")
|
Style editLine = res.createSubstyle(STYLE_EDIT_LINE).backgroundImageId("editbox_background")
|
||||||
.setPadding(5,6,5,6).setMargins(2,2,2,2).minWidth(40)
|
.setPadding(5,6,5,6).setMargins(2,2,2,2).minWidth(40)
|
||||||
.fontFace("Arial").fontFamily(FontFamily.SansSerif).fontSize(16);
|
.fontFace("Arial").fontFamily(FontFamily.SansSerif).fontSize(16);
|
||||||
Style editBox = res.createSubstyle("EDIT_BOX").backgroundImageId("editbox_background")
|
Style editBox = res.createSubstyle(STYLE_EDIT_BOX).backgroundImageId("editbox_background")
|
||||||
.setPadding(5,6,5,6).setMargins(2,2,2,2).minWidth(100).minHeight(60).layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT)
|
.setPadding(5,6,5,6).setMargins(2,2,2,2).minWidth(100).minHeight(60).layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT)
|
||||||
.fontFace("Courier New").fontFamily(FontFamily.MonoSpace).fontSize(16);
|
.fontFace("Courier New").fontFamily(FontFamily.MonoSpace).fontSize(16);
|
||||||
|
|
||||||
|
@ -858,6 +973,25 @@ Rect decodeRect(string s) {
|
||||||
return Rect(0,0,0,0);
|
return Rect(0,0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private import std.array : split;
|
||||||
|
|
||||||
|
/// Decode color list attribute, e.g.: "#84A, #99FFFF" -> [0x8844aa, 0x99ffff]
|
||||||
|
uint[] decodeFocusRectColors(string s) {
|
||||||
|
if (s.equal("@null"))
|
||||||
|
return [COLOR_UNSPECIFIED];
|
||||||
|
string[] colors = split(s, ",");
|
||||||
|
if (colors.length < 1)
|
||||||
|
return null;
|
||||||
|
uint[] res = new uint[colors.length];
|
||||||
|
for (int i = 0; i < colors.length; i++) {
|
||||||
|
uint cl = decodeHexColor(colors[i], COLOR_UNSPECIFIED);
|
||||||
|
if (cl == COLOR_UNSPECIFIED)
|
||||||
|
return null;
|
||||||
|
res[i] = cl;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/// parses string like "Left|VCenter" to bit set of Align flags
|
/// parses string like "Left|VCenter" to bit set of Align flags
|
||||||
ubyte decodeAlignment(string s) {
|
ubyte decodeAlignment(string s) {
|
||||||
ubyte res = 0;
|
ubyte res = 0;
|
||||||
|
@ -983,6 +1117,8 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
||||||
style.alpha = decodeDimension(elem.tag.attr["alpha"]);
|
style.alpha = decodeDimension(elem.tag.attr["alpha"]);
|
||||||
if ("textFlags" in elem.tag.attr)
|
if ("textFlags" in elem.tag.attr)
|
||||||
style.textFlags = decodeTextFlags(elem.tag.attr["textFlags"]);
|
style.textFlags = decodeTextFlags(elem.tag.attr["textFlags"]);
|
||||||
|
if ("focusRectColors" in elem.tag.attr)
|
||||||
|
style.focusRectColors = decodeFocusRectColors(elem.tag.attr["focusRectColors"]);
|
||||||
foreach(item; elem.elements) {
|
foreach(item; elem.elements) {
|
||||||
if (allowStates && item.tag.name.equal("state")) {
|
if (allowStates && item.tag.name.equal("state")) {
|
||||||
uint stateMask = 0;
|
uint stateMask = 0;
|
||||||
|
@ -998,6 +1134,13 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
||||||
string drawablevalue = attrValue(item, "value");
|
string drawablevalue = attrValue(item, "value");
|
||||||
if (drawableid)
|
if (drawableid)
|
||||||
style.setCustomDrawable(drawableid, drawablevalue);
|
style.setCustomDrawable(drawableid, drawablevalue);
|
||||||
|
} else if (item.tag.name.equal("color")) {
|
||||||
|
// <color id="buttons_panel_color" value="#303080"/>
|
||||||
|
string colorid = attrValue(item, "id");
|
||||||
|
string colorvalue = attrValue(item, "value");
|
||||||
|
uint color = decodeHexColor(colorvalue, COLOR_TRANSPARENT);
|
||||||
|
if (colorid)
|
||||||
|
style.setCustomColor(colorid, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1011,7 +1154,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
||||||
* <?xml version="1.0" encoding="utf-8"?>
|
* <?xml version="1.0" encoding="utf-8"?>
|
||||||
* <theme id="theme_custom" parent="theme_default">
|
* <theme id="theme_custom" parent="theme_default">
|
||||||
* <style id="BUTTON"
|
* <style id="BUTTON"
|
||||||
* backgroundImageId="btn_default_small"
|
* backgroundImageId="btn_background"
|
||||||
* >
|
* >
|
||||||
* </style>
|
* </style>
|
||||||
* </theme>
|
* </theme>
|
||||||
|
@ -1092,6 +1235,33 @@ Theme loadTheme(string resourceId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// custom drawable attribute container for styles
|
||||||
|
class DrawableAttribute {
|
||||||
|
protected string _id;
|
||||||
|
protected string _drawableId;
|
||||||
|
protected DrawableRef _drawable;
|
||||||
|
protected bool _initialized;
|
||||||
|
this(string id, string drawableId) {
|
||||||
|
_id = id;
|
||||||
|
_drawableId = drawableId;
|
||||||
|
}
|
||||||
|
@property string id() const { return _id; }
|
||||||
|
@property string drawableId() const { return _drawableId; }
|
||||||
|
@property void drawableId(string newDrawable) { _drawableId = newDrawable; clear(); }
|
||||||
|
@property ref DrawableRef drawable() const {
|
||||||
|
if (!_drawable.isNull)
|
||||||
|
return (cast(DrawableAttribute)this)._drawable;
|
||||||
|
(cast(DrawableAttribute)this)._drawable = drawableCache.get(_id);
|
||||||
|
(cast(DrawableAttribute)this)._initialized = true;
|
||||||
|
return (cast(DrawableAttribute)this)._drawable;
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
_drawable.clear();
|
||||||
|
_initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
shared static ~this() {
|
shared static ~this() {
|
||||||
currentTheme = null;
|
currentTheme = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,14 +67,14 @@ class TabItemWidget : HorizontalLayout {
|
||||||
@property TabItem tabItem() { return _item; }
|
@property TabItem tabItem() { return _item; }
|
||||||
@property TabControl tabControl() { return cast(TabControl)parent; }
|
@property TabControl tabControl() { return cast(TabControl)parent; }
|
||||||
this(TabItem item, bool enableCloseButton = true) {
|
this(TabItem item, bool enableCloseButton = true) {
|
||||||
styleId = "TAB_UP_BUTTON";
|
styleId = STYLE_TAB_UP_BUTTON;
|
||||||
_enableCloseButton = enableCloseButton;
|
_enableCloseButton = enableCloseButton;
|
||||||
_icon = new ImageWidget();
|
_icon = new ImageWidget();
|
||||||
_label = new TextWidget();
|
_label = new TextWidget();
|
||||||
_label.styleId = "TAB_UP_BUTTON_TEXT";
|
_label.styleId = STYLE_TAB_UP_BUTTON_TEXT;
|
||||||
_label.state = State.Parent;
|
_label.state = State.Parent;
|
||||||
_closeButton = new ImageButton("CLOSE");
|
_closeButton = new ImageButton("CLOSE");
|
||||||
_closeButton.styleId = "BUTTON_TRANSPARENT";
|
_closeButton.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||||
_closeButton.drawableId = "close";
|
_closeButton.drawableId = "close";
|
||||||
_closeButton.trackHover = true;
|
_closeButton.trackHover = true;
|
||||||
_closeButton.onClickListener = &onClick;
|
_closeButton.onClickListener = &onClick;
|
||||||
|
@ -167,7 +167,7 @@ class TabItemList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// tab header - tab labels, with optional More button
|
/// tab header - tab labels, with optional More button
|
||||||
class TabControl : WidgetGroup {
|
class TabControl : WidgetGroupDefaultDrawing {
|
||||||
protected TabItemList _items;
|
protected TabItemList _items;
|
||||||
protected ImageButton _moreButton;
|
protected ImageButton _moreButton;
|
||||||
protected bool _enableCloseButton;
|
protected bool _enableCloseButton;
|
||||||
|
@ -186,11 +186,11 @@ class TabControl : WidgetGroup {
|
||||||
super(ID);
|
super(ID);
|
||||||
_items = new TabItemList();
|
_items = new TabItemList();
|
||||||
_moreButton = new ImageButton("MORE", "tab_more");
|
_moreButton = new ImageButton("MORE", "tab_more");
|
||||||
_moreButton.styleId = "BUTTON_TRANSPARENT";
|
_moreButton.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||||
_moreButton.onClickListener = &onClick;
|
_moreButton.onClickListener = &onClick;
|
||||||
_moreButton.margins(Rect(3,3,3,6));
|
_moreButton.margins(Rect(3,3,3,6));
|
||||||
_enableCloseButton = true;
|
_enableCloseButton = true;
|
||||||
styleId = "TAB_UP";
|
styleId = STYLE_TAB_UP;
|
||||||
addChild(_moreButton); // first child is always MORE button, the rest corresponds to tab list
|
addChild(_moreButton); // first child is always MORE button, the rest corresponds to tab list
|
||||||
}
|
}
|
||||||
/// returns tab count
|
/// returns tab count
|
||||||
|
@ -338,24 +338,6 @@ class TabControl : WidgetGroup {
|
||||||
}
|
}
|
||||||
//Log.d("tabControl.layout exit");
|
//Log.d("tabControl.layout exit");
|
||||||
}
|
}
|
||||||
/// Draw widget at its position to buffer
|
|
||||||
override void onDraw(DrawBuf buf) {
|
|
||||||
//Log.d("tabControl.onDraw enter");
|
|
||||||
if (visibility != Visibility.Visible)
|
|
||||||
return;
|
|
||||||
super.onDraw(buf);
|
|
||||||
Rect rc = _pos;
|
|
||||||
applyMargins(rc);
|
|
||||||
applyPadding(rc);
|
|
||||||
auto saver = ClipRectSaver(buf, rc);
|
|
||||||
for (int i = 0; i < _children.count; i++) {
|
|
||||||
Widget item = _children.get(i);
|
|
||||||
if (item.visibility != Visibility.Visible)
|
|
||||||
continue;
|
|
||||||
item.onDraw(buf);
|
|
||||||
}
|
|
||||||
//Log.d("tabControl.onDraw exit");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string _selectedTabId;
|
protected string _selectedTabId;
|
||||||
|
|
||||||
|
@ -388,7 +370,7 @@ class TabHost : FrameLayout, TabHandler {
|
||||||
_tabControl = tabControl;
|
_tabControl = tabControl;
|
||||||
if (_tabControl !is null)
|
if (_tabControl !is null)
|
||||||
_tabControl.onTabChangedListener = &onTabChanged;
|
_tabControl.onTabChangedListener = &onTabChanged;
|
||||||
styleId = "TAB_HOST";
|
styleId = STYLE_TAB_HOST;
|
||||||
}
|
}
|
||||||
protected TabControl _tabControl;
|
protected TabControl _tabControl;
|
||||||
/// get currently set control widget
|
/// get currently set control widget
|
||||||
|
@ -478,7 +460,7 @@ class TabWidget : VerticalLayout, TabHandler {
|
||||||
_tabControl = new TabControl("TAB_CONTROL");
|
_tabControl = new TabControl("TAB_CONTROL");
|
||||||
_tabHost = new TabHost("TAB_HOST", _tabControl);
|
_tabHost = new TabHost("TAB_HOST", _tabControl);
|
||||||
_tabControl.onTabChangedListener.connect(this);
|
_tabControl.onTabChangedListener.connect(this);
|
||||||
styleId = "TAB_WIDGET";
|
styleId = STYLE_TAB_WIDGET;
|
||||||
addChild(_tabControl);
|
addChild(_tabControl);
|
||||||
addChild(_tabHost);
|
addChild(_tabHost);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,10 @@ class TreeItem {
|
||||||
return cast(TreeItems)p;
|
return cast(TreeItems)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@property TreeItem parent() { return _parent; }
|
@property TreeItem parent() { return _parent; }
|
||||||
@property protected TreeItem parent(TreeItem p) { _parent = p; return this; }
|
@property protected TreeItem parent(TreeItem p) { _parent = p; return this; }
|
||||||
@property string id() { return _id; }
|
@property string id() { return _id; }
|
||||||
|
@ -197,6 +201,29 @@ class TreeItem {
|
||||||
return _parent.topParent;
|
return _parent.topParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected int _intParam;
|
||||||
|
protected Object _objectParam;
|
||||||
|
|
||||||
|
@property int intParam() {
|
||||||
|
return _intParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property TreeItem intParam(int value) {
|
||||||
|
_intParam = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property Object objectParam() {
|
||||||
|
return _objectParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property TreeItem objectParam(Object value) {
|
||||||
|
_objectParam = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// returns true if item has at least one child
|
/// returns true if item has at least one child
|
||||||
@property bool hasChildren() { return childCount > 0; }
|
@property bool hasChildren() { return childCount > 0; }
|
||||||
|
|
||||||
|
@ -440,7 +467,7 @@ class TreeItemWidget : HorizontalLayout {
|
||||||
|
|
||||||
this(TreeItem item) {
|
this(TreeItem item) {
|
||||||
super(item.id);
|
super(item.id);
|
||||||
styleId = "TREE_ITEM";
|
styleId = STYLE_TREE_ITEM;
|
||||||
|
|
||||||
clickable = true;
|
clickable = true;
|
||||||
focusable = true;
|
focusable = true;
|
||||||
|
@ -458,7 +485,7 @@ class TreeItemWidget : HorizontalLayout {
|
||||||
_tab.maxWidth = w;
|
_tab.maxWidth = w;
|
||||||
if (_item.hasChildren) {
|
if (_item.hasChildren) {
|
||||||
_expander = new ImageWidget("expander", _item.hasChildren && _item.expanded ? "arrow_right_down_black" : "arrow_right_hollow");
|
_expander = new ImageWidget("expander", _item.hasChildren && _item.expanded ? "arrow_right_down_black" : "arrow_right_hollow");
|
||||||
_expander.styleId = "TREE_ITEM_EXPAND_ICON";
|
_expander.styleId = STYLE_TREE_ITEM_EXPAND_ICON;
|
||||||
_expander.clickable = true;
|
_expander.clickable = true;
|
||||||
_expander.trackHover = true;
|
_expander.trackHover = true;
|
||||||
//_expander.setState(State.Parent);
|
//_expander.setState(State.Parent);
|
||||||
|
@ -484,11 +511,11 @@ class TreeItemWidget : HorizontalLayout {
|
||||||
};
|
};
|
||||||
if (_item.iconRes.length > 0) {
|
if (_item.iconRes.length > 0) {
|
||||||
_icon = new ImageWidget("icon", _item.iconRes);
|
_icon = new ImageWidget("icon", _item.iconRes);
|
||||||
_icon.styleId = "TREE_ITEM_ICON";
|
_icon.styleId = STYLE_TREE_ITEM_ICON;
|
||||||
_icon.setState(State.Parent);
|
_icon.setState(State.Parent);
|
||||||
}
|
}
|
||||||
_label = new TextWidget("label", _item.text);
|
_label = new TextWidget("label", _item.text);
|
||||||
_label.styleId = "TREE_ITEM_LABEL";
|
_label.styleId = STYLE_TREE_ITEM_LABEL;
|
||||||
_label.setState(State.Parent);
|
_label.setState(State.Parent);
|
||||||
// append children
|
// append children
|
||||||
addChild(_tab);
|
addChild(_tab);
|
||||||
|
|
|
@ -38,6 +38,7 @@ module dlangui.widgets.widget;
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
public import dlangui.core.events;
|
public import dlangui.core.events;
|
||||||
public import dlangui.core.i18n;
|
public import dlangui.core.i18n;
|
||||||
|
public import dlangui.core.collections;
|
||||||
public import dlangui.widgets.styles;
|
public import dlangui.widgets.styles;
|
||||||
|
|
||||||
public import dlangui.graphics.drawbuf;
|
public import dlangui.graphics.drawbuf;
|
||||||
|
@ -315,6 +316,7 @@ class Widget {
|
||||||
requestLayout();
|
requestLayout();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
immutable static int FOCUS_RECT_PADDING = 2;
|
||||||
/// get padding (between background bounds and content of widget)
|
/// get padding (between background bounds and content of widget)
|
||||||
@property Rect padding() const {
|
@property Rect padding() const {
|
||||||
// get max padding from style padding and background drawable padding
|
// get max padding from style padding and background drawable padding
|
||||||
|
@ -331,6 +333,10 @@ class Widget {
|
||||||
if (p.bottom < dp.bottom)
|
if (p.bottom < dp.bottom)
|
||||||
p.bottom = dp.bottom;
|
p.bottom = dp.bottom;
|
||||||
}
|
}
|
||||||
|
if ((focusable || ((state & State.Parent) && parent.focusable)) && focusRectColors) {
|
||||||
|
// add two pixels to padding when focus rect is required - one pixel for focus rect, one for additional space
|
||||||
|
p.offset(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
/// set padding for widget - override one from style
|
/// set padding for widget - override one from style
|
||||||
|
@ -359,6 +365,11 @@ class Widget {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns colors to draw focus rectangle (one for solid, two for vertical gradient) or null if no focus rect should be drawn for style
|
||||||
|
@property const(uint[]) focusRectColors() const {
|
||||||
|
return style.focusRectColors;
|
||||||
|
}
|
||||||
|
|
||||||
/// background drawable
|
/// background drawable
|
||||||
@property DrawableRef backgroundDrawable() const {
|
@property DrawableRef backgroundDrawable() const {
|
||||||
return stateStyle.backgroundDrawable;
|
return stateStyle.backgroundDrawable;
|
||||||
|
@ -588,10 +599,10 @@ class Widget {
|
||||||
|
|
||||||
protected bool _focusable;
|
protected bool _focusable;
|
||||||
/// whether widget can be focused
|
/// whether widget can be focused
|
||||||
@property bool focusable() { return _focusable; }
|
@property bool focusable() const { return _focusable; }
|
||||||
@property Widget focusable(bool flg) { _focusable = flg; return this; }
|
@property Widget focusable(bool flg) { _focusable = flg; return this; }
|
||||||
|
|
||||||
@property bool focused() {
|
@property bool focused() const {
|
||||||
return (window !is null && window.focusedWidget is this && (state & State.Focused));
|
return (window !is null && window.focusedWidget is this && (state & State.Focused));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +705,7 @@ class Widget {
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
if (!rc.intersects(clipRect))
|
if (!rc.intersects(clipRect))
|
||||||
return; // out of clip rectangle
|
return; // out of clip rectangle
|
||||||
if (focusable) {
|
if (canFocus) {
|
||||||
TabOrderInfo item = new TabOrderInfo(this, rc);
|
TabOrderInfo item = new TabOrderInfo(this, rc);
|
||||||
results ~= item;
|
results ~= item;
|
||||||
return;
|
return;
|
||||||
|
@ -839,9 +850,9 @@ class Widget {
|
||||||
return parent.visible;
|
return parent.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if widget is focusable and visible
|
/// returns true if widget is focusable and visible and enabled
|
||||||
@property bool canFocus() {
|
@property bool canFocus() {
|
||||||
return focusable && visible;
|
return focusable && visible && enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// sets focus to this widget or suitable focusable child, returns previously focused widget
|
/// sets focus to this widget or suitable focusable child, returns previously focused widget
|
||||||
|
@ -1056,19 +1067,31 @@ class Widget {
|
||||||
// summarize margins, padding, and content size
|
// summarize margins, padding, and content size
|
||||||
int dx = m.left + m.right + p.left + p.right + contentWidth;
|
int dx = m.left + m.right + p.left + p.right + contentWidth;
|
||||||
int dy = m.top + m.bottom + p.top + p.bottom + contentHeight;
|
int dy = m.top + m.bottom + p.top + p.bottom + contentHeight;
|
||||||
|
// check for fixed size set in layoutWidth, layoutHeight
|
||||||
|
int lh = layoutHeight;
|
||||||
|
int lw = layoutWidth;
|
||||||
|
if (!isSpecialSize(lh))
|
||||||
|
dy = lh;
|
||||||
|
if (!isSpecialSize(lw))
|
||||||
|
dx = lw;
|
||||||
// apply min/max width and height constraints
|
// apply min/max width and height constraints
|
||||||
int minw = minWidth;
|
int minw = minWidth;
|
||||||
int maxw = maxWidth;
|
int maxw = maxWidth;
|
||||||
int minh = minHeight;
|
int minh = minHeight;
|
||||||
int maxh = maxHeight;
|
int maxh = maxHeight;
|
||||||
if (dx < minw)
|
if (minw != SIZE_UNSPECIFIED && dx < minw)
|
||||||
dx = minw;
|
dx = minw;
|
||||||
if (dy < minh)
|
if (minh != SIZE_UNSPECIFIED && dy < minh)
|
||||||
dy = minh;
|
dy = minh;
|
||||||
if (maxw != SIZE_UNSPECIFIED && dx > maxw)
|
if (maxw != SIZE_UNSPECIFIED && dx > maxw)
|
||||||
dx = maxw;
|
dx = maxw;
|
||||||
if (maxh != SIZE_UNSPECIFIED && dy > maxh)
|
if (maxh != SIZE_UNSPECIFIED && dy > maxh)
|
||||||
dy = maxh;
|
dy = maxh;
|
||||||
|
// apply FILL_PARENT
|
||||||
|
//if (parentWidth != SIZE_UNSPECIFIED && layoutWidth == FILL_PARENT)
|
||||||
|
// dx = parentWidth;
|
||||||
|
//if (parentHeight != SIZE_UNSPECIFIED && layoutHeight == FILL_PARENT)
|
||||||
|
// dy = parentHeight;
|
||||||
// apply max parent size constraint
|
// apply max parent size constraint
|
||||||
if (parentWidth != SIZE_UNSPECIFIED && dx > parentWidth)
|
if (parentWidth != SIZE_UNSPECIFIED && dx > parentWidth)
|
||||||
dx = parentWidth;
|
dx = parentWidth;
|
||||||
|
@ -1095,6 +1118,14 @@ class Widget {
|
||||||
_needLayout = false;
|
_needLayout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// draws focus rectangle, if enabled in styles
|
||||||
|
void drawFocusRect(DrawBuf buf, Rect rc) {
|
||||||
|
const uint[] colors = focusRectColors;
|
||||||
|
if (colors) {
|
||||||
|
buf.drawFocusRect(rc, colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw widget at its position to buffer
|
/// Draw widget at its position to buffer
|
||||||
void onDraw(DrawBuf buf) {
|
void onDraw(DrawBuf buf) {
|
||||||
if (visibility != Visibility.Visible)
|
if (visibility != Visibility.Visible)
|
||||||
|
@ -1107,6 +1138,10 @@ class Widget {
|
||||||
bg.drawTo(buf, rc, state);
|
bg.drawTo(buf, rc, state);
|
||||||
}
|
}
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
|
if (state & State.Focused) {
|
||||||
|
rc.expand(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
|
||||||
|
drawFocusRect(buf, rc);
|
||||||
|
}
|
||||||
_needDraw = false;
|
_needDraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,15 +1264,15 @@ class Widget {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns parent widget, null for top level widget
|
/// returns parent widget, null for top level widget
|
||||||
@property Widget parent() { return _parent; }
|
@property Widget parent() const { return cast(Widget)_parent; }
|
||||||
/// sets parent for widget
|
/// sets parent for widget
|
||||||
@property Widget parent(Widget parent) { _parent = parent; return this; }
|
@property Widget parent(Widget parent) { _parent = parent; return this; }
|
||||||
/// returns window (if widget or its parent is attached to window)
|
/// returns window (if widget or its parent is attached to window)
|
||||||
@property Window window() {
|
@property Window window() const {
|
||||||
Widget p = this;
|
Widget p = cast(Widget)this;
|
||||||
while (p !is null) {
|
while (p !is null) {
|
||||||
if (p._window !is null)
|
if (p._window !is null)
|
||||||
return p._window;
|
return cast(Window)p._window;
|
||||||
p = p.parent;
|
p = p.parent;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -1251,80 +1286,6 @@ class Widget {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** object list holder, owning its objects - on destroy of holder, all own objects will be destroyed */
|
|
||||||
struct ObjectList(T) {
|
|
||||||
protected T[] _list;
|
|
||||||
protected int _count;
|
|
||||||
/** returns count of items */
|
|
||||||
@property int count() const { return _count; }
|
|
||||||
/** get item by index */
|
|
||||||
T get(int index) {
|
|
||||||
assert(index >= 0 && index < _count, "child index out of range");
|
|
||||||
return _list[index];
|
|
||||||
}
|
|
||||||
/** add item to list */
|
|
||||||
T add(T item) {
|
|
||||||
if (_list.length <= _count) // resize
|
|
||||||
_list.length = _list.length < 4 ? 4 : _list.length * 2;
|
|
||||||
_list[_count++] = item;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
/** add item to list */
|
|
||||||
T insert(T item, int index = -1) {
|
|
||||||
if (index > _count || index < 0)
|
|
||||||
index = _count;
|
|
||||||
if (_list.length <= _count) // resize
|
|
||||||
_list.length = _list.length < 4 ? 4 : _list.length * 2;
|
|
||||||
for (int i = _count; i > index; i--)
|
|
||||||
_list[i] = _list[i - 1];
|
|
||||||
_list[index] = item;
|
|
||||||
_count++;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
/** find child index for item, return -1 if not found */
|
|
||||||
int indexOf(T item) {
|
|
||||||
for (int i = 0; i < _count; i++)
|
|
||||||
if (_list[i] == item)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/** find child index for item by id, return -1 if not found */
|
|
||||||
static if (__traits(hasMember, T, "compareId")) {
|
|
||||||
int indexOf(string id) {
|
|
||||||
for (int i = 0; i < _count; i++)
|
|
||||||
if (_list[i].compareId(id))
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** remove item from list, return removed item */
|
|
||||||
T remove(int index) {
|
|
||||||
assert(index >= 0 && index < _count, "child index out of range");
|
|
||||||
T item = _list[index];
|
|
||||||
for (int i = index; i < _count - 1; i++)
|
|
||||||
_list[i] = _list[i + 1];
|
|
||||||
_count--;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
/** Replace item with another value, destroy old value. */
|
|
||||||
void replace(T item, int index) {
|
|
||||||
T old = _list[index];
|
|
||||||
_list[index] = item;
|
|
||||||
destroy(old);
|
|
||||||
}
|
|
||||||
/** remove and destroy all items */
|
|
||||||
void clear() {
|
|
||||||
for (int i = 0; i < _count; i++) {
|
|
||||||
destroy(_list[i]);
|
|
||||||
_list[i] = null;
|
|
||||||
}
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
~this() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Widget list holder. */
|
/** Widget list holder. */
|
||||||
alias WidgetList = ObjectList!Widget;
|
alias WidgetList = ObjectList!Widget;
|
||||||
|
|
||||||
|
@ -1375,6 +1336,34 @@ class WidgetGroup : Widget {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** WidgetGroup with default drawing of children (just draw all children) */
|
||||||
|
class WidgetGroupDefaultDrawing : WidgetGroup {
|
||||||
|
/// empty parameter list constructor - for usage by factory
|
||||||
|
this() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
/// create with ID parameter
|
||||||
|
this(string ID) {
|
||||||
|
super(ID);
|
||||||
|
}
|
||||||
|
/// 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);
|
||||||
|
applyPadding(rc);
|
||||||
|
auto saver = ClipRectSaver(buf, rc);
|
||||||
|
for (int i = 0; i < _children.count; i++) {
|
||||||
|
Widget item = _children.get(i);
|
||||||
|
if (item.visibility != Visibility.Visible)
|
||||||
|
continue;
|
||||||
|
item.onDraw(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
immutable long ONE_SECOND = 10000000L;
|
immutable long ONE_SECOND = 10000000L;
|
||||||
|
|
||||||
/// Helper to handle animation progress
|
/// Helper to handle animation progress
|
||||||
|
|