Merge branch 'master' of github.com:buggins/dlangui
|
@ -89,7 +89,6 @@
|
|||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>2</cRuntime>
|
||||
<additionalOptions />
|
||||
<preBuildCommand />
|
||||
<postBuildCommand />
|
||||
|
@ -184,7 +183,6 @@
|
|||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).lib</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>1</cRuntime>
|
||||
<additionalOptions />
|
||||
<preBuildCommand />
|
||||
<postBuildCommand />
|
||||
|
@ -357,6 +355,7 @@
|
|||
<File path="src\dlangui\dialogs\msgbox.d" />
|
||||
</Folder>
|
||||
<Folder name="graphics">
|
||||
<File path="src\dlangui\graphics\colors.d" />
|
||||
<File path="src\dlangui\graphics\drawbuf.d" />
|
||||
<File path="src\dlangui\graphics\fonts.d" />
|
||||
<File path="src\dlangui\graphics\ftfonts.d" />
|
||||
|
|
|
@ -89,7 +89,6 @@
|
|||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>2</cRuntime>
|
||||
<additionalOptions>-profile</additionalOptions>
|
||||
<preBuildCommand />
|
||||
<postBuildCommand />
|
||||
|
@ -184,7 +183,6 @@
|
|||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>1</cRuntime>
|
||||
<additionalOptions />
|
||||
<preBuildCommand />
|
||||
<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));
|
||||
WidgetGroup buttons1 = new HorizontalLayout();
|
||||
buttons1.addChild(new Button("btn1", "Button 1"d));
|
||||
buttons1.addChild(new Button("btn2", "Button 2"d));
|
||||
buttons1.addChild(new Button("btn3", "Button 3"d));
|
||||
buttons1.addChild(new ResizerWidget());
|
||||
buttons1.addChild(new Button("btn4", "Button 4"d));
|
||||
buttons1.addChild(new TextWidget(null, "Button widgets: "d));
|
||||
buttons1.addChild(new Button("btn1", "Button"d));
|
||||
buttons1.addChild((new Button("btn2", "Disabled Button"d)).enabled(false));
|
||||
buttons1.addChild(new TextWidget(null, "ImageButton widgets: "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);
|
||||
|
||||
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 TextWidget(null, "CheckBoxes in HorizontalLayout"d));
|
||||
WidgetGroup buttons2 = new HorizontalLayout();
|
||||
|
@ -463,7 +482,7 @@ extern (C) int UIAppMain(string[] args) {
|
|||
layout3.addChild(new VSpacer());
|
||||
layout3.addChild(new TextWidget(null, "In vertical layouts:"d));
|
||||
HorizontalLayout hlayout2 = new HorizontalLayout();
|
||||
hlayout2.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
|
||||
hlayout2.layoutHeight(FILL_PARENT); //layoutWidth(FILL_PARENT).
|
||||
|
||||
buttons1 = new VerticalLayout();
|
||||
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 EditLine("edit2", "Some text for parameter 2"d)).layoutWidth(FILL_PARENT));
|
||||
// row 3
|
||||
table.addChild((new TextWidget(null, "Param 3"d)).alignment(Align.Right | Align.VCenter));
|
||||
table.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT));
|
||||
|
||||
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).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]);
|
||||
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);
|
||||
// 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);
|
||||
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 EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
|
||||
// row 6
|
||||
table2.addChild((new TextWidget(null, "Param 6 - 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 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).enabled(false));
|
||||
// row 7
|
||||
table2.addChild((new TextWidget(null, "Param 7 - 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 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).enabled(false));
|
||||
// row 8
|
||||
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));
|
||||
|
|
|
@ -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"?>
|
||||
<!-- 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">
|
||||
|
||||
<!-- 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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
android:state_enabled="true"
|
||||
android:drawable="@drawable/btn_check_off_holo_light" />
|
||||
android:drawable="@drawable/btn_check_off" />
|
||||
<item android:state_checked="true"
|
||||
android:state_enabled="true"
|
||||
android:drawable="@drawable/btn_check_on_holo_light" />
|
||||
android:drawable="@drawable/btn_check_on" />
|
||||
|
||||
|
||||
<!-- Disabled states -->
|
||||
|
||||
<item android:state_checked="true" android:state_window_focused="false"
|
||||
android:drawable="@drawable/btn_check_on_disabled_holo_light" />
|
||||
<item android:state_checked="false" android:state_window_focused="false"
|
||||
android:drawable="@drawable/btn_check_off_disabled_holo_light" />
|
||||
<item android:state_checked="true"
|
||||
android:drawable="@drawable/btn_check_on_disabled" />
|
||||
<item android:state_checked="false"
|
||||
android:drawable="@drawable/btn_check_off_disabled" />
|
||||
|
||||
<item android:state_checked="true" android:state_focused="true"
|
||||
android:drawable="@drawable/btn_check_on_disabled_focused_holo_light" />
|
||||
<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" />
|
||||
<item android:state_checked="false" android:drawable="@drawable/btn_check_off" />
|
||||
<item android:state_checked="true" android:drawable="@drawable/btn_check_on" />
|
||||
|
||||
</selector>
|
||||
|
|
|
@ -1,59 +1,34 @@
|
|||
<?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">
|
||||
<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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
android:drawable="@drawable/btn_radio_off_holo_light" />
|
||||
android:drawable="@drawable/btn_radio_off" />
|
||||
<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 -->
|
||||
|
||||
<item android:state_checked="true" android:state_window_focused="false"
|
||||
android:drawable="@drawable/btn_radio_on_disabled_holo_light" />
|
||||
<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" />
|
||||
<item android:state_checked="false" android:drawable="@drawable/btn_radio_off_disabled" />
|
||||
<item android:state_checked="true" android:drawable="@drawable/btn_radio_on_disabled" />
|
||||
|
||||
</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"?>
|
||||
<!--
|
||||
/* //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">
|
||||
<item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/editbox_background_disabled_focus_yellow" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/editbox_background_focus_yellow" />
|
||||
<item android:state_enabled="false" android:drawable="@drawable/editbox_background_disabled" />
|
||||
<item android:drawable="@drawable/editbox_background_normal" />
|
||||
<item android:state_focused="true" android:state_enabled="false" android:drawable="editbox_background_disabled_focus" />
|
||||
<item android:state_focused="true" android:drawable="editbox_background_focus" />
|
||||
<item android:state_enabled="false" android:drawable="editbox_background_disabled" />
|
||||
<item android:drawable="editbox_background_normal" />
|
||||
</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"?>
|
||||
<theme id="theme_default" fontSize="15" >
|
||||
<style id="BUTTON"
|
||||
backgroundImageId="btn_default_small"
|
||||
backgroundImageId="btn_background"
|
||||
align="Center"
|
||||
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"
|
||||
backgroundImageId="btn_default_small_transparent"
|
||||
backgroundImageId="btn_background_transparent"
|
||||
align="Center"
|
||||
/>
|
||||
<style id="BUTTON_LABEL"
|
||||
layoutWidth="FILL_PARENT"
|
||||
margins="2,2,2,2"
|
||||
align="Left|VCenter"
|
||||
/>
|
||||
<style id="BUTTON_ICON"
|
||||
textFlags="UnderlineHotKeys"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<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"
|
||||
margins="2,2,2,2"
|
||||
padding="1,1,1,1"
|
||||
/>
|
||||
align="Left|VCenter"
|
||||
>
|
||||
<state state_enabled="false" textColor="#A0000000"/>
|
||||
</style>
|
||||
<style id="HSPACER"
|
||||
layoutWidth="FILL_PARENT"
|
||||
layoutWeight="100"
|
||||
|
@ -31,9 +74,13 @@
|
|||
minHeight="5"
|
||||
/>
|
||||
<style id="BUTTON_NOMARGINS"
|
||||
backgroundImageId="btn_default_small"
|
||||
backgroundImageId="btn_background"
|
||||
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_down" value="scrollbar_btn_down"/>
|
||||
<drawable id="scrollbar_button_left" value="scrollbar_btn_left"/>
|
||||
|
@ -134,43 +181,39 @@
|
|||
<style id="LIST_ITEM"
|
||||
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"
|
||||
backgroundImageId="editbox_background"
|
||||
backgroundImageId="combobox_background"
|
||||
padding="2,2,2,2"
|
||||
margins="2,2,2,2"
|
||||
minWidth="40"
|
||||
fontFace="Arial"
|
||||
fontFamily="SansSerif"
|
||||
fontSize="16"
|
||||
/>
|
||||
<style id="COMBO_BOX_BODY"
|
||||
padding="2,2,2,2"
|
||||
minWidth="40"
|
||||
fontFace="Arial"
|
||||
fontFamily="SansSerif"
|
||||
fontSize="16"
|
||||
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"
|
||||
backgroundImageId="editbox_background"
|
||||
padding="5,6,5,6"
|
||||
padding="2,2,2,2"
|
||||
margins="2,2,2,2"
|
||||
minWidth="100"
|
||||
minHeight="60"
|
||||
layoutWidth="FILL_PARENT"
|
||||
layoutHeight="FILL_PARENT"
|
||||
fontFace="Courier New"
|
||||
fontFamily="MonoSpace"
|
||||
fontSize="16"
|
||||
/>
|
||||
<style id="TREE_ITEM"
|
||||
padding="2,2,2,2"
|
||||
|
|
|
@ -64,6 +64,7 @@ public import dlangui.widgets.grid;
|
|||
public import dlangui.widgets.tree;
|
||||
public import dlangui.widgets.combobox;
|
||||
public import dlangui.widgets.popup;
|
||||
public import dlangui.graphics.colors;
|
||||
public import dlangui.graphics.fonts;
|
||||
public import dlangui.graphics.drawbuf;
|
||||
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;
|
||||
|
||||
this(UIString caption, Window parentWindow = null, uint flags = DialogFlag.Modal) {
|
||||
super("dlg");
|
||||
super("dialog-main-widget");
|
||||
_caption = caption;
|
||||
_parentWindow = parentWindow;
|
||||
_flags = flags;
|
||||
|
@ -155,8 +155,11 @@ class Dialog : VerticalLayout {
|
|||
uint wflags = 0;
|
||||
if (_flags & DialogFlag.Modal)
|
||||
wflags |= WindowFlag.Modal;
|
||||
if (_flags & DialogFlag.Resizable)
|
||||
if (_flags & DialogFlag.Resizable) {
|
||||
wflags |= WindowFlag.Resizable;
|
||||
layoutWidth = FILL_PARENT;
|
||||
layoutHeight = FILL_PARENT;
|
||||
}
|
||||
_window = Platform.instance.createWindow(_caption, _parentWindow, wflags);
|
||||
if (_window && _icon)
|
||||
_window.windowIcon = drawableCache.getImage(_icon);
|
||||
|
|
|
@ -133,13 +133,6 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
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() {
|
||||
return openDirectory(parentDir(_path), _path);
|
||||
}
|
||||
|
@ -234,12 +227,12 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
|
||||
protected ListWidget createRootsList() {
|
||||
ListWidget res = new ListWidget("ROOTS_LIST");
|
||||
res.styleId = "EDIT_BOX";
|
||||
res.styleId = STYLE_EDIT_BOX;
|
||||
WidgetListAdapter adapter = new WidgetListAdapter();
|
||||
foreach(ref RootEntry root; _roots) {
|
||||
ImageTextButton btn = new ImageTextButton(null, root.icon, root.label);
|
||||
btn.orientation = Orientation.Vertical;
|
||||
btn.styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
||||
btn.styleId = STYLE_TRANSPARENT_BUTTON_BACKGROUND;
|
||||
btn.focusable = false;
|
||||
adapter.widgets.add(btn);
|
||||
}
|
||||
|
@ -310,11 +303,11 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
|||
layoutWidth(FILL_PARENT);
|
||||
layoutWidth(FILL_PARENT);
|
||||
minWidth = 600;
|
||||
minHeight = 400;
|
||||
//minHeight = 400;
|
||||
|
||||
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.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() {
|
||||
_fileList.setFocus();
|
||||
}
|
||||
|
@ -403,17 +418,17 @@ class FilePathPanelItem : HorizontalLayout {
|
|||
Listener!OnPathSelectionHandler onPathSelectionListener;
|
||||
this(string path) {
|
||||
super(null);
|
||||
styleId = "LIST_ITEM";
|
||||
styleId = STYLE_LIST_ITEM;
|
||||
_path = path;
|
||||
string fname = isRoot(path) ? path : baseName(path);
|
||||
_text = new TextWidget(null, toUTF32(fname));
|
||||
_text.styleId = "BUTTON_TRANSPARENT";
|
||||
_text.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||
_text.clickable = true;
|
||||
_text.onClickListener = &onTextClick;
|
||||
//_text.backgroundColor = 0xC0FFFF;
|
||||
_text.state = State.Parent;
|
||||
_button = new ImageButton(null, "scrollbar_btn_right");
|
||||
_button.styleId = "BUTTON_TRANSPARENT";
|
||||
_button.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||
_button.focusable = false;
|
||||
_button.onClickListener = &onButtonClick;
|
||||
//_button.backgroundColor = 0xC0FFC0;
|
||||
|
@ -458,7 +473,7 @@ class FilePathPanelItem : HorizontalLayout {
|
|||
}
|
||||
|
||||
/// Panel with buttons - path segments - for fast navigation to subdirs.
|
||||
class FilePathPanelButtons : WidgetGroup {
|
||||
class FilePathPanelButtons : WidgetGroupDefaultDrawing {
|
||||
protected string _path;
|
||||
Listener!OnPathSelectionHandler onPathSelectionListener;
|
||||
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;
|
||||
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).
|
||||
|
@ -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)
|
||||
DrawBuf transformColors(ref ColorTransform transform) {
|
||||
return this;
|
||||
|
|
|
@ -62,9 +62,9 @@ class GLDrawBuf : DrawBuf {
|
|||
|
||||
/// reserved for hardware-accelerated drawing - ends drawing batch
|
||||
override void afterDrawing() {
|
||||
setOrthoProjection(_dx, _dy);
|
||||
glSupport.setOrthoProjection(_dx, _dy);
|
||||
_scene.draw();
|
||||
flushGL();
|
||||
glSupport.flushGL();
|
||||
destroy(_scene);
|
||||
_scene = null;
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ private class GLImageCache {
|
|||
_drawbuf = null;
|
||||
}
|
||||
if (_textureId != 0) {
|
||||
deleteTexture(_textureId);
|
||||
glSupport.deleteTexture(_textureId);
|
||||
_textureId = 0;
|
||||
}
|
||||
}
|
||||
|
@ -254,14 +254,14 @@ private class GLImageCache {
|
|||
return; // no draw buffer!!!
|
||||
if (_textureId == 0) {
|
||||
//CRLog::debug("updateTexture - new texture");
|
||||
_textureId = genTexture();
|
||||
_textureId = glSupport.genTexture();
|
||||
if (!_textureId)
|
||||
return;
|
||||
}
|
||||
//CRLog::debug("updateTexture - setting image %dx%d", _drawbuf.width, _drawbuf.height);
|
||||
uint * pixels = _drawbuf.scanLine(0);
|
||||
if (!setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)pixels)) {
|
||||
deleteTexture(_textureId);
|
||||
if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)pixels)) {
|
||||
glSupport.deleteTexture(_textureId);
|
||||
_textureId = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ private class GLImageCache {
|
|||
if (_needUpdateTexture)
|
||||
updateTexture();
|
||||
if (_textureId != 0) {
|
||||
if (!isTexture(_textureId)) {
|
||||
if (!glSupport.isTexture(_textureId)) {
|
||||
Log.e("Invalid texture ", _textureId);
|
||||
return;
|
||||
}
|
||||
|
@ -371,12 +371,12 @@ private class GLImageCache {
|
|||
dstrc.bottom -= clip.bottom;
|
||||
}
|
||||
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);
|
||||
|
||||
if (rotationAngle) {
|
||||
// unset rotation
|
||||
setRotation(rx, ry, 0);
|
||||
glSupport.setRotation(rx, ry, 0);
|
||||
// glMatrixMode(GL_PROJECTION);
|
||||
// glPopMatrix();
|
||||
// checkError("pop matrix");
|
||||
|
@ -576,7 +576,7 @@ private class GLGlyphCache {
|
|||
_drawbuf = null;
|
||||
}
|
||||
if (_textureId != 0) {
|
||||
deleteTexture(_textureId);
|
||||
glSupport.deleteTexture(_textureId);
|
||||
_textureId = 0;
|
||||
}
|
||||
}
|
||||
|
@ -589,7 +589,7 @@ private class GLGlyphCache {
|
|||
return; // no draw buffer!!!
|
||||
if (_textureId == 0) {
|
||||
//CRLog::debug("updateTexture - new texture");
|
||||
_textureId = genTexture();
|
||||
_textureId = glSupport.genTexture();
|
||||
if (!_textureId)
|
||||
return;
|
||||
}
|
||||
|
@ -600,8 +600,8 @@ private class GLGlyphCache {
|
|||
_rgbaBuffer.length = len;
|
||||
for (int i = 0; i < len; i++)
|
||||
_rgbaBuffer[i] = ((cast(uint)pixels[i]) << 24) | 0x00FFFFFF;
|
||||
if (!setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)_rgbaBuffer.ptr)) {
|
||||
deleteTexture(_textureId);
|
||||
if (!glSupport.setTextureImage(_textureId, _drawbuf.width, _drawbuf.height, cast(ubyte*)_rgbaBuffer.ptr)) {
|
||||
glSupport.deleteTexture(_textureId);
|
||||
_textureId = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ private class GLGlyphCache {
|
|||
if (_needUpdateTexture)
|
||||
updateTexture();
|
||||
if (_textureId != 0) {
|
||||
if (!isTexture(_textureId)) {
|
||||
if (!glSupport.isTexture(_textureId)) {
|
||||
Log.e("Invalid texture ", _textureId);
|
||||
return;
|
||||
}
|
||||
|
@ -693,7 +693,7 @@ private class GLGlyphCache {
|
|||
}
|
||||
if (!dstrc.empty) {
|
||||
//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;
|
||||
}
|
||||
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"
|
||||
];
|
||||
}
|
||||
/* Convenient wrapper around glGetError()
|
||||
/**
|
||||
* Convenient wrapper around glGetError()
|
||||
* TODO use one of the DEBUG extensions instead
|
||||
*/
|
||||
bool checkError(string context="", string file=__FILE__, int line=__LINE__)
|
||||
|
@ -67,295 +68,6 @@ bool checkError(string context="", string file=__FILE__, int line=__LINE__)
|
|||
return false;
|
||||
}
|
||||
|
||||
immutable float Z_2D = -2.0f;
|
||||
void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
|
||||
float[6 * 4] colors;
|
||||
LVGLFillColor(color1, colors.ptr + 4*0, 1);
|
||||
LVGLFillColor(color4, colors.ptr + 4*1, 1);
|
||||
LVGLFillColor(color3, colors.ptr + 4*2, 1);
|
||||
LVGLFillColor(color1, colors.ptr + 4*3, 1);
|
||||
LVGLFillColor(color3, colors.ptr + 4*4, 1);
|
||||
LVGLFillColor(color2, colors.ptr + 4*5, 1);
|
||||
float x0 = cast(float)(rc.left);
|
||||
float y0 = cast(float)(bufferDy-rc.top);
|
||||
float x1 = cast(float)(rc.right);
|
||||
float y1 = cast(float)(bufferDy-rc.bottom);
|
||||
|
||||
// don't flip for framebuffer
|
||||
if (currentFramebufferId) {
|
||||
y0 = cast(float)(rc.top);
|
||||
y1 = cast(float)(rc.bottom);
|
||||
}
|
||||
|
||||
float[3 * 6] vertices = [
|
||||
x0,y0,Z_2D,
|
||||
x0,y1,Z_2D,
|
||||
x1,y1,Z_2D,
|
||||
x0,y0,Z_2D,
|
||||
x1,y1,Z_2D,
|
||||
x1,y0,Z_2D];
|
||||
if (_solidFillProgram !is null) {
|
||||
//Log.d("solid fill: vertices ", vertices, " colors ", colors);
|
||||
_solidFillProgram.execute(vertices, colors);
|
||||
} else
|
||||
Log.e("No program");
|
||||
}
|
||||
|
||||
void drawColorAndTextureRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color, bool linear) {
|
||||
//Log.v("drawColorAndTextureRect tx=", textureId, " src=", srcrc, " dst=", dstrc);
|
||||
drawColorAndTextureRect(textureId, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear);
|
||||
}
|
||||
|
||||
void drawColorAndTextureRect(uint textureId, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) {
|
||||
float[6*4] colors;
|
||||
LVGLFillColor(color, colors.ptr, 6);
|
||||
float dstx0 = cast(float)xx;
|
||||
float dsty0 = cast(float)(bufferDy - (yy));
|
||||
float dstx1 = cast(float)(xx + dx);
|
||||
float dsty1 = cast(float)(bufferDy - (yy + dy));
|
||||
|
||||
// don't flip for framebuffer
|
||||
if (currentFramebufferId) {
|
||||
dsty0 = cast(float)((yy));
|
||||
dsty1 = cast(float)((yy + dy));
|
||||
}
|
||||
|
||||
float srcx0 = srcx / cast(float)tdx;
|
||||
float srcy0 = srcy / cast(float)tdy;
|
||||
float srcx1 = (srcx + srcdx) / cast(float)tdx;
|
||||
float srcy1 = (srcy + srcdy) / cast(float)tdy;
|
||||
float[3 * 6] vertices = [dstx0,dsty0,Z_2D,
|
||||
dstx0,dsty1,Z_2D,
|
||||
dstx1,dsty1,Z_2D,
|
||||
dstx0,dsty0,Z_2D,
|
||||
dstx1,dsty1,Z_2D,
|
||||
dstx1,dsty0,Z_2D];
|
||||
float[2 * 6] texcoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy1, srcx0,srcy0, srcx1,srcy1, srcx1,srcy0];
|
||||
_textureProgram.execute(vertices, texcoords, colors, textureId, linear);
|
||||
//drawColorAndTextureRect(vertices, texcoords, colors, textureId, linear);
|
||||
}
|
||||
|
||||
/// generate new texture ID
|
||||
uint genTexture() {
|
||||
GLuint textureId = 0;
|
||||
glGenTextures(1, &textureId);
|
||||
return textureId;
|
||||
}
|
||||
|
||||
/// delete OpenGL texture
|
||||
void deleteTexture(ref uint textureId) {
|
||||
if (!textureId)
|
||||
return;
|
||||
if (glIsTexture(textureId) != GL_TRUE) {
|
||||
Log.e("Invalid texture ", textureId);
|
||||
return;
|
||||
}
|
||||
GLuint id = textureId;
|
||||
glDeleteTextures(1, &id);
|
||||
checkError("glDeleteTextures");
|
||||
textureId = 0;
|
||||
}
|
||||
|
||||
/// call glFlush
|
||||
void flushGL() {
|
||||
glFlush();
|
||||
checkError("glFlush");
|
||||
}
|
||||
|
||||
bool setTextureImage(uint textureId, int dx, int dy, ubyte * pixels) {
|
||||
//checkError("before setTextureImage");
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
checkError("updateTexture - glActiveTexture");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("updateTexture - glBindTexture");
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
checkError("updateTexture - glPixelStorei");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
|
||||
if (!glIsTexture(textureId))
|
||||
Log.e("second test - invalid texture passed to CRGLSupportImpl::setTextureImage");
|
||||
|
||||
// ORIGINAL: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
checkError("updateTexture - glTexImage2D");
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
Log.e("Cannot set image for texture");
|
||||
return false;
|
||||
}
|
||||
checkError("after setTextureImage");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setTextureImageAlpha(uint textureId, int dx, int dy, ubyte * pixels) {
|
||||
checkError("before setTextureImageAlpha");
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
checkError("updateTexture - glActiveTexture");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("setTextureImageAlpha - glBindTexture");
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
checkError("setTextureImageAlpha - glPixelStorei");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
|
||||
if (!glIsTexture(textureId))
|
||||
Log.e("second test: invalid texture passed to CRGLSupportImpl::setTextureImageAlpha");
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, dx, dy, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
|
||||
checkError("setTextureImageAlpha - glTexImage2D");
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
Log.e("Cannot set image for texture");
|
||||
return false;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
checkError("after setTextureImageAlpha");
|
||||
return true;
|
||||
}
|
||||
|
||||
private uint currentFramebufferId;
|
||||
|
||||
/// returns texture ID for buffer, 0 if failed
|
||||
bool createFramebuffer(ref uint textureId, ref uint framebufferId, int dx, int dy) {
|
||||
checkError("before createFramebuffer");
|
||||
bool res = true;
|
||||
textureId = framebufferId = 0;
|
||||
textureId = genTexture();
|
||||
if (!textureId)
|
||||
return false;
|
||||
GLuint fid = 0;
|
||||
glGenFramebuffers(1, &fid);
|
||||
if (checkError("createFramebuffer glGenFramebuffersOES")) return false;
|
||||
framebufferId = fid;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
|
||||
if (checkError("createFramebuffer glBindFramebuffer")) return false;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("glBindTexture(GL_TEXTURE_2D, _textureId)");
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dx, dy, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
|
||||
checkError("glTexImage2D");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("texParameter");
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
|
||||
checkError("glFramebufferTexture2D");
|
||||
// Always check that our framebuffer is ok
|
||||
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
Log.e("glFramebufferTexture2D failed");
|
||||
res = false;
|
||||
}
|
||||
checkError("glCheckFramebufferStatus");
|
||||
//glClearColor(0.5f, 0, 0, 1);
|
||||
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
checkError("glClearColor");
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
checkError("glClear");
|
||||
checkError("after createFramebuffer");
|
||||
//CRLog::trace("CRGLSupportImpl::createFramebuffer %d,%d texture=%d, buffer=%d", dx, dy, textureId, framebufferId);
|
||||
currentFramebufferId = framebufferId;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("createFramebuffer - glBindTexture(0)");
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
checkError("createFramebuffer - glBindFramebuffer(0)");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void deleteFramebuffer(ref uint framebufferId) {
|
||||
//CRLog::debug("GLDrawBuf::deleteFramebuffer");
|
||||
if (framebufferId != 0) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
checkError("deleteFramebuffer - glBindFramebuffer");
|
||||
GLuint fid = framebufferId;
|
||||
glDeleteFramebuffers(1, &fid);
|
||||
checkError("deleteFramebuffer - glDeleteFramebuffer");
|
||||
}
|
||||
//CRLog::trace("CRGLSupportImpl::deleteFramebuffer(%d)", framebufferId);
|
||||
framebufferId = 0;
|
||||
checkError("after deleteFramebuffer");
|
||||
currentFramebufferId = 0;
|
||||
}
|
||||
|
||||
bool bindFramebuffer(uint framebufferId) {
|
||||
//CRLog::trace("CRGLSupportImpl::bindFramebuffer(%d)", framebufferId);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
|
||||
currentFramebufferId = framebufferId;
|
||||
return !checkError("glBindFramebuffer");
|
||||
}
|
||||
|
||||
/// projection matrix
|
||||
//private mat4 m;
|
||||
/// current gl buffer width
|
||||
private int bufferDx;
|
||||
/// current gl buffer height
|
||||
private int bufferDy;
|
||||
|
||||
//private float[16] matrix;
|
||||
private float[16] qtmatrix;
|
||||
|
||||
void QMatrix4x4_ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
|
||||
{
|
||||
// Bail out if the projection volume is zero-sized.
|
||||
if (left == right || bottom == top || nearPlane == farPlane)
|
||||
return;
|
||||
|
||||
// Construct the projection.
|
||||
float width = right - left;
|
||||
float invheight = top - bottom;
|
||||
float clip = farPlane - nearPlane;
|
||||
float[4][4] m;
|
||||
m[0][0] = 2.0f / width;
|
||||
m[1][0] = 0.0f;
|
||||
m[2][0] = 0.0f;
|
||||
m[3][0] = -(left + right) / width;
|
||||
m[0][1] = 0.0f;
|
||||
m[1][1] = 2.0f / invheight;
|
||||
m[2][1] = 0.0f;
|
||||
m[3][1] = -(top + bottom) / invheight;
|
||||
m[0][2] = 0.0f;
|
||||
m[1][2] = 0.0f;
|
||||
m[2][2] = -2.0f / clip;
|
||||
m[3][2] = -(nearPlane + farPlane) / clip;
|
||||
m[0][3] = 0.0f;
|
||||
m[1][3] = 0.0f;
|
||||
m[2][3] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
for (int y = 0; y < 4; y++)
|
||||
for (int x = 0; x < 4; x++)
|
||||
qtmatrix[y * 4 + x] = m[y][x];
|
||||
}
|
||||
|
||||
void setOrthoProjection(int dx, int dy) {
|
||||
bufferDx = dx;
|
||||
bufferDy = dy;
|
||||
QMatrix4x4_ortho(0, dx, 0, dy, 0.5f, 50.0f);
|
||||
glViewport(0, 0, dx, dy);
|
||||
checkError("glViewport");
|
||||
}
|
||||
|
||||
class GLProgram {
|
||||
@property abstract string vertexSource();
|
||||
|
@ -503,7 +215,7 @@ class SolidFillProgram : GLProgram {
|
|||
bind();
|
||||
//glUniformMatrix4fv(matrixLocation, 1, false, m.value_ptr);
|
||||
//glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr);
|
||||
glUniformMatrix4fv(matrixLocation, 1, false, qtmatrix.ptr);
|
||||
glUniformMatrix4fv(matrixLocation, 1, false, glSupport.qtmatrix.ptr);
|
||||
checkError("glUniformMatrix4fv");
|
||||
}
|
||||
|
||||
|
@ -704,57 +416,366 @@ class TextureProgram : SolidFillProgram {
|
|||
}
|
||||
}
|
||||
|
||||
__gshared TextureProgram _textureProgram;
|
||||
__gshared SolidFillProgram _solidFillProgram;
|
||||
__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;
|
||||
}
|
||||
|
||||
bool initShaders() {
|
||||
if (_textureProgram is null) {
|
||||
_textureProgram = new TextureProgram();
|
||||
if (!_textureProgram.compile())
|
||||
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) {
|
||||
float[6 * 4] colors;
|
||||
LVGLFillColor(color1, colors.ptr + 4*0, 1);
|
||||
LVGLFillColor(color4, colors.ptr + 4*1, 1);
|
||||
LVGLFillColor(color3, colors.ptr + 4*2, 1);
|
||||
LVGLFillColor(color1, colors.ptr + 4*3, 1);
|
||||
LVGLFillColor(color3, colors.ptr + 4*4, 1);
|
||||
LVGLFillColor(color2, colors.ptr + 4*5, 1);
|
||||
float x0 = cast(float)(rc.left);
|
||||
float y0 = cast(float)(bufferDy-rc.top);
|
||||
float x1 = cast(float)(rc.right);
|
||||
float y1 = cast(float)(bufferDy-rc.bottom);
|
||||
|
||||
// don't flip for framebuffer
|
||||
if (currentFramebufferId) {
|
||||
y0 = cast(float)(rc.top);
|
||||
y1 = cast(float)(rc.bottom);
|
||||
}
|
||||
|
||||
float[3 * 6] vertices = [
|
||||
x0,y0,Z_2D,
|
||||
x0,y1,Z_2D,
|
||||
x1,y1,Z_2D,
|
||||
x0,y0,Z_2D,
|
||||
x1,y1,Z_2D,
|
||||
x1,y0,Z_2D];
|
||||
if (_solidFillProgram !is null) {
|
||||
//Log.d("solid fill: vertices ", vertices, " colors ", colors);
|
||||
_solidFillProgram.execute(vertices, colors);
|
||||
} else
|
||||
Log.e("No program");
|
||||
}
|
||||
|
||||
void drawColorAndTextureRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color, bool linear) {
|
||||
//Log.v("drawColorAndTextureRect tx=", textureId, " src=", srcrc, " dst=", dstrc);
|
||||
drawColorAndTextureRect(textureId, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear);
|
||||
}
|
||||
|
||||
void drawColorAndTextureRect(uint textureId, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) {
|
||||
float[6*4] colors;
|
||||
LVGLFillColor(color, colors.ptr, 6);
|
||||
float dstx0 = cast(float)xx;
|
||||
float dsty0 = cast(float)(bufferDy - (yy));
|
||||
float dstx1 = cast(float)(xx + dx);
|
||||
float dsty1 = cast(float)(bufferDy - (yy + dy));
|
||||
|
||||
// don't flip for framebuffer
|
||||
if (currentFramebufferId) {
|
||||
dsty0 = cast(float)((yy));
|
||||
dsty1 = cast(float)((yy + dy));
|
||||
}
|
||||
|
||||
float srcx0 = srcx / cast(float)tdx;
|
||||
float srcy0 = srcy / cast(float)tdy;
|
||||
float srcx1 = (srcx + srcdx) / cast(float)tdx;
|
||||
float srcy1 = (srcy + srcdy) / cast(float)tdy;
|
||||
float[3 * 6] vertices = [dstx0,dsty0,Z_2D,
|
||||
dstx0,dsty1,Z_2D,
|
||||
dstx1,dsty1,Z_2D,
|
||||
dstx0,dsty0,Z_2D,
|
||||
dstx1,dsty1,Z_2D,
|
||||
dstx1,dsty0,Z_2D];
|
||||
float[2 * 6] texcoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy1, srcx0,srcy0, srcx1,srcy1, srcx1,srcy0];
|
||||
_textureProgram.execute(vertices, texcoords, colors, textureId, linear);
|
||||
//drawColorAndTextureRect(vertices, texcoords, colors, textureId, linear);
|
||||
}
|
||||
|
||||
/// generate new texture ID
|
||||
uint genTexture() {
|
||||
GLuint textureId = 0;
|
||||
glGenTextures(1, &textureId);
|
||||
return textureId;
|
||||
}
|
||||
|
||||
/// delete OpenGL texture
|
||||
void deleteTexture(ref uint textureId) {
|
||||
if (!textureId)
|
||||
return;
|
||||
if (glIsTexture(textureId) != GL_TRUE) {
|
||||
Log.e("Invalid texture ", textureId);
|
||||
return;
|
||||
}
|
||||
GLuint id = textureId;
|
||||
glDeleteTextures(1, &id);
|
||||
checkError("glDeleteTextures");
|
||||
textureId = 0;
|
||||
}
|
||||
|
||||
/// call glFlush
|
||||
void flushGL() {
|
||||
glFlush();
|
||||
checkError("glFlush");
|
||||
}
|
||||
|
||||
bool setTextureImage(uint textureId, int dx, int dy, ubyte * pixels) {
|
||||
//checkError("before setTextureImage");
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
checkError("updateTexture - glActiveTexture");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("updateTexture - glBindTexture");
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
checkError("updateTexture - glPixelStorei");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("updateTexture - glTexParameteri");
|
||||
|
||||
if (!glIsTexture(textureId))
|
||||
Log.e("second test - invalid texture passed to CRGLSupportImpl::setTextureImage");
|
||||
|
||||
// ORIGINAL: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
checkError("updateTexture - glTexImage2D");
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
Log.e("Cannot set image for texture");
|
||||
return false;
|
||||
}
|
||||
checkError("after setTextureImage");
|
||||
return true;
|
||||
}
|
||||
if (_solidFillProgram is null) {
|
||||
_solidFillProgram = new SolidFillProgram();
|
||||
if (!_solidFillProgram.compile())
|
||||
|
||||
bool setTextureImageAlpha(uint textureId, int dx, int dy, ubyte * pixels) {
|
||||
checkError("before setTextureImageAlpha");
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
checkError("updateTexture - glActiveTexture");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("setTextureImageAlpha - glBindTexture");
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
checkError("setTextureImageAlpha - glPixelStorei");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("setTextureImageAlpha - glTexParameteri");
|
||||
|
||||
if (!glIsTexture(textureId))
|
||||
Log.e("second test: invalid texture passed to CRGLSupportImpl::setTextureImageAlpha");
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, dx, dy, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
|
||||
checkError("setTextureImageAlpha - glTexImage2D");
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
Log.e("Cannot set image for texture");
|
||||
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;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("updateTexture - glBindTexture(0)");
|
||||
checkError("after setTextureImageAlpha");
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
private uint currentFramebufferId;
|
||||
|
||||
/// returns texture ID for buffer, 0 if failed
|
||||
bool createFramebuffer(ref uint textureId, ref uint framebufferId, int dx, int dy) {
|
||||
checkError("before createFramebuffer");
|
||||
bool res = true;
|
||||
textureId = framebufferId = 0;
|
||||
textureId = genTexture();
|
||||
if (!textureId)
|
||||
return false;
|
||||
GLuint fid = 0;
|
||||
glGenFramebuffers(1, &fid);
|
||||
if (checkError("createFramebuffer glGenFramebuffersOES")) return false;
|
||||
framebufferId = fid;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
|
||||
if (checkError("createFramebuffer glBindFramebuffer")) return false;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkError("glBindTexture(GL_TEXTURE_2D, _textureId)");
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dx, dy, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
|
||||
checkError("glTexImage2D");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
checkError("texParameter");
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
checkError("texParameter");
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
|
||||
checkError("glFramebufferTexture2D");
|
||||
// Always check that our framebuffer is ok
|
||||
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
Log.e("glFramebufferTexture2D failed");
|
||||
res = false;
|
||||
}
|
||||
checkError("glCheckFramebufferStatus");
|
||||
//glClearColor(0.5f, 0, 0, 1);
|
||||
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
checkError("glClearColor");
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
checkError("glClear");
|
||||
checkError("after createFramebuffer");
|
||||
//CRLog::trace("CRGLSupportImpl::createFramebuffer %d,%d texture=%d, buffer=%d", dx, dy, textureId, framebufferId);
|
||||
currentFramebufferId = framebufferId;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
checkError("createFramebuffer - glBindTexture(0)");
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
checkError("createFramebuffer - glBindFramebuffer(0)");
|
||||
|
||||
return res;
|
||||
}
|
||||
matrix2.copyDataTo(m);
|
||||
*/
|
||||
|
||||
void deleteFramebuffer(ref uint framebufferId) {
|
||||
//CRLog::debug("GLDrawBuf::deleteFramebuffer");
|
||||
if (framebufferId != 0) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
checkError("deleteFramebuffer - glBindFramebuffer");
|
||||
GLuint fid = framebufferId;
|
||||
glDeleteFramebuffers(1, &fid);
|
||||
checkError("deleteFramebuffer - glDeleteFramebuffer");
|
||||
}
|
||||
//CRLog::trace("CRGLSupportImpl::deleteFramebuffer(%d)", framebufferId);
|
||||
framebufferId = 0;
|
||||
checkError("after deleteFramebuffer");
|
||||
currentFramebufferId = 0;
|
||||
}
|
||||
|
||||
bool bindFramebuffer(uint framebufferId) {
|
||||
//CRLog::trace("CRGLSupportImpl::bindFramebuffer(%d)", framebufferId);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
|
||||
currentFramebufferId = framebufferId;
|
||||
return !checkError("glBindFramebuffer");
|
||||
}
|
||||
|
||||
/// projection matrix
|
||||
//private mat4 m;
|
||||
/// current gl buffer width
|
||||
private int bufferDx;
|
||||
/// current gl buffer height
|
||||
private int bufferDy;
|
||||
//private float[16] matrix;
|
||||
private float[16] qtmatrix;
|
||||
|
||||
void QMatrix4x4_ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
|
||||
{
|
||||
// Bail out if the projection volume is zero-sized.
|
||||
if (left == right || bottom == top || nearPlane == farPlane)
|
||||
return;
|
||||
|
||||
// Construct the projection.
|
||||
float width = right - left;
|
||||
float invheight = top - bottom;
|
||||
float clip = farPlane - nearPlane;
|
||||
float[4][4] m;
|
||||
m[0][0] = 2.0f / width;
|
||||
m[1][0] = 0.0f;
|
||||
m[2][0] = 0.0f;
|
||||
m[3][0] = -(left + right) / width;
|
||||
m[0][1] = 0.0f;
|
||||
m[1][1] = 2.0f / invheight;
|
||||
m[2][1] = 0.0f;
|
||||
m[3][1] = -(top + bottom) / invheight;
|
||||
m[0][2] = 0.0f;
|
||||
m[1][2] = 0.0f;
|
||||
m[2][2] = -2.0f / clip;
|
||||
m[3][2] = -(nearPlane + farPlane) / clip;
|
||||
m[0][3] = 0.0f;
|
||||
m[1][3] = 0.0f;
|
||||
m[2][3] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
for (int y = 0; y < 4; y++)
|
||||
for (int x = 0; x < 4; x++)
|
||||
qtmatrix[y * 4 + x] = m[y][x];
|
||||
}
|
||||
|
||||
void setOrthoProjection(int dx, int dy) {
|
||||
bufferDx = dx;
|
||||
bufferDy = dy;
|
||||
QMatrix4x4_ortho(0, dx, 0, dy, 0.5f, 50.0f);
|
||||
glViewport(0, 0, dx, dy);
|
||||
checkError("glViewport");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ version (USE_DLIBIMAGE) {
|
|||
|
||||
import dlangui.core.logger;
|
||||
import dlangui.core.types;
|
||||
import dlangui.graphics.colors;
|
||||
import dlangui.graphics.drawbuf;
|
||||
import std.stream;
|
||||
import std.conv : to;
|
||||
|
|
|
@ -28,6 +28,7 @@ module dlangui.graphics.resources;
|
|||
|
||||
import dlangui.graphics.images;
|
||||
import dlangui.graphics.drawbuf;
|
||||
import dlangui.graphics.colors;
|
||||
import dlangui.core.logger;
|
||||
import std.file;
|
||||
import std.algorithm;
|
||||
|
@ -93,22 +94,7 @@ class FrameDrawable : Drawable {
|
|||
@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
|
||||
static uint decodeDimension(string s) {
|
||||
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) {
|
||||
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_default", "android:state_default", State.Default, 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_checkable", "android:state_checkable", State.Checkable, stateMask, stateValue);
|
||||
|
|
|
@ -107,11 +107,13 @@ class Window {
|
|||
Log.d("onResize ", _dx, "x", _dy);
|
||||
long measureStart = currentTimeMillis;
|
||||
measure();
|
||||
//Log.d("measured size: ", _mainWidget.measuredWidth, "x", _mainWidget.measuredHeight);
|
||||
long measureEnd = currentTimeMillis;
|
||||
Log.d("measure took ", measureEnd - measureStart, " ms");
|
||||
layout();
|
||||
long layoutEnd = currentTimeMillis;
|
||||
Log.d("layout took ", layoutEnd - measureEnd, " ms");
|
||||
//Log.d("layout position: ", _mainWidget.pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ class SDLWindow : Window {
|
|||
version(USE_OPENGL) {
|
||||
if (_enableOpengl)
|
||||
windowFlags |= SDL_WINDOW_OPENGL;
|
||||
if (!_glSupport)
|
||||
_glSupport = new GLSupport();
|
||||
}
|
||||
_win = SDL_CreateWindow(toUTF8(_caption).toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
700, 500,
|
||||
|
@ -127,7 +129,7 @@ class SDLWindow : Window {
|
|||
} else if (!_gl3Reloaded) {
|
||||
DerelictGL3.reload();
|
||||
_gl3Reloaded = true;
|
||||
if (!initShaders())
|
||||
if (!glSupport.valid && !glSupport.initShaders())
|
||||
_enableOpengl = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ class Win32ColorDrawBuf : ColorDrawBufBase {
|
|||
/// create resized copy of ColorDrawBuf
|
||||
this(ColorDrawBuf v, int dx, int dy) {
|
||||
this(dx, dy);
|
||||
resetClipping();
|
||||
fill(0xFFFFFFFF);
|
||||
if (_dx == dx && _dy == dy)
|
||||
drawImage(0, 0, v);
|
||||
|
@ -87,7 +88,7 @@ class Win32ColorDrawBuf : ColorDrawBufBase {
|
|||
//return CreateBitmap(_dx, _dy, 1, 1, buf.ptr);
|
||||
}
|
||||
/// destroy object, but leave bitmap as is
|
||||
HBITMAP destoryLeavingBitmap() {
|
||||
HBITMAP destroyLeavingBitmap() {
|
||||
HBITMAP res = _drawbmp;
|
||||
_drawbmp = null;
|
||||
destroy(this);
|
||||
|
|
|
@ -154,10 +154,12 @@ version (USE_OPENGL) {
|
|||
|
||||
class Win32Window : Window {
|
||||
Win32Platform _platform;
|
||||
|
||||
HWND _hwnd;
|
||||
version (USE_OPENGL) {
|
||||
HGLRC _hGLRC; // opengl context
|
||||
HPALETTE _hPalette;
|
||||
GLSupport _gl;
|
||||
}
|
||||
dstring _caption;
|
||||
Win32ColorDrawBuf _drawbuf;
|
||||
|
@ -167,6 +169,9 @@ class Win32Window : Window {
|
|||
Win32Window w32parent = cast(Win32Window)parent;
|
||||
HWND parenthwnd = w32parent ? w32parent._hwnd : null;
|
||||
_platform = platform;
|
||||
version (USE_OPENGL) {
|
||||
_gl = new GLSupport();
|
||||
}
|
||||
_caption = windowCaption;
|
||||
_flags = flags;
|
||||
uint ws = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||
|
@ -199,7 +204,9 @@ class Win32Window : Window {
|
|||
_hPalette = setupPalette(hDC);
|
||||
_hGLRC = wglCreateContext(hDC);
|
||||
if (_hGLRC) {
|
||||
|
||||
wglMakeCurrent(hDC, _hGLRC);
|
||||
_glSupport = _gl;
|
||||
|
||||
if (!DERELICT_GL3_RELOADED) {
|
||||
// run this code only once
|
||||
|
@ -208,7 +215,7 @@ class Win32Window : Window {
|
|||
import derelict.opengl3.gl3;
|
||||
DerelictGL3.reload();
|
||||
// successful
|
||||
if (initShaders()) {
|
||||
if (glSupport.initShaders()) {
|
||||
setOpenglEnabled();
|
||||
useOpengl = true;
|
||||
} else {
|
||||
|
@ -218,7 +225,7 @@ class Win32Window : Window {
|
|||
Log.e("Derelict exception", e);
|
||||
}
|
||||
} else {
|
||||
if (initShaders()) {
|
||||
if (glSupport.initShaders()) {
|
||||
setOpenglEnabled();
|
||||
useOpengl = true;
|
||||
} else {
|
||||
|
@ -252,6 +259,7 @@ class Win32Window : Window {
|
|||
//scope(exit) EndPaint(_hwnd, &ps);
|
||||
HDC hdc = GetDC(_hwnd);
|
||||
wglMakeCurrent(hdc, _hGLRC);
|
||||
_glSupport = _gl;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glViewport(0, 0, _dx, _dy);
|
||||
float a = 1.0f;
|
||||
|
@ -288,7 +296,10 @@ class Win32Window : Window {
|
|||
version (USE_OPENGL) {
|
||||
import derelict.opengl3.wgl;
|
||||
if (_hGLRC) {
|
||||
uninitShaders();
|
||||
glSupport.uninitShaders();
|
||||
destroy(_glSupport);
|
||||
_glSupport = null;
|
||||
_gl = null;
|
||||
wglMakeCurrent (null, null) ;
|
||||
wglDeleteContext(_hGLRC);
|
||||
_hGLRC = null;
|
||||
|
@ -440,7 +451,7 @@ class Win32Window : Window {
|
|||
resizedicon.invertAlpha();
|
||||
ICONINFO ii;
|
||||
HBITMAP mask = resizedicon.createTransparencyBitmap();
|
||||
HBITMAP color = resizedicon.destoryLeavingBitmap();
|
||||
HBITMAP color = resizedicon.destroyLeavingBitmap();
|
||||
ii.fIcon = TRUE;
|
||||
ii.xHotspot = 0;
|
||||
ii.yHotspot = 0;
|
||||
|
@ -448,8 +459,8 @@ class Win32Window : Window {
|
|||
ii.hbmColor = color;
|
||||
_icon = CreateIconIndirect(&ii);
|
||||
if (_icon) {
|
||||
SendMessage(_hwnd, WM_SETICON, ICON_SMALL, cast(int)_icon);
|
||||
SendMessage(_hwnd, WM_SETICON, ICON_BIG, cast(int)_icon);
|
||||
SendMessageW(_hwnd, WM_SETICON, ICON_SMALL, cast(LPARAM)_icon);
|
||||
SendMessageW(_hwnd, WM_SETICON, ICON_BIG, cast(LPARAM)_icon);
|
||||
} else {
|
||||
Log.e("failed to create icon");
|
||||
}
|
||||
|
@ -470,7 +481,7 @@ class Win32Window : Window {
|
|||
}
|
||||
|
||||
void onPaint() {
|
||||
Log.d("onPaint()");
|
||||
debug(DebugRedraw) Log.d("onPaint()");
|
||||
long paintStart = currentTimeMillis;
|
||||
version (USE_OPENGL) {
|
||||
if (useOpengl && _hGLRC) {
|
||||
|
@ -482,7 +493,7 @@ class Win32Window : Window {
|
|||
paintUsingGDI();
|
||||
}
|
||||
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;
|
||||
|
@ -951,12 +962,17 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
{
|
||||
if (window !is null) {
|
||||
WINDOWPOS * pos = cast(WINDOWPOS*)lParam;
|
||||
Log.d("WM_WINDOWPOSCHANGED: ", *pos);
|
||||
GetClientRect(hwnd, &rect);
|
||||
int dx = rect.right - rect.left;
|
||||
int dy = rect.bottom - rect.top;
|
||||
//window.onResize(pos.cx, pos.cy);
|
||||
window.onResize(dx, dy);
|
||||
InvalidateRect(hwnd, null, FALSE);
|
||||
//if (!(pos.flags & 0x8000)) { //SWP_NOACTIVATE)) {
|
||||
//if (pos.x > -30000) {
|
||||
int dx = rect.right - rect.left;
|
||||
int dy = rect.bottom - rect.top;
|
||||
window.onResize(dx, dy);
|
||||
InvalidateRect(hwnd, null, FALSE);
|
||||
//}
|
||||
//}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -73,13 +73,24 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
|||
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) {
|
||||
showPopup();
|
||||
if (enabled)
|
||||
showPopup();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected ImageButton createButton() {
|
||||
ImageButton res = new ImageButton("COMBOBOX_BUTTON", "scrollbar_btn_down");
|
||||
res.styleId = STYLE_COMBO_BOX_BUTTON;
|
||||
res.layoutWeight = 0;
|
||||
res.onClickListener = this;
|
||||
return res;
|
||||
|
@ -99,7 +110,7 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
|||
_popupList = createPopup();
|
||||
_popup = window.showPopup(_popupList, this, PopupAlign.Below | PopupAlign.FitAnchorSize);
|
||||
_popup.flags = PopupFlags.CloseOnClickOutside;
|
||||
_popup.styleId = "POPUP_MENU";
|
||||
_popup.styleId = STYLE_POPUP_MENU;
|
||||
_popup.onPopupCloseListener = delegate (PopupWidget source) {
|
||||
_popup = null;
|
||||
_popupList = null;
|
||||
|
@ -121,6 +132,8 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
|||
super(ID);
|
||||
_adapter = adapter;
|
||||
_ownAdapter = ownAdapter;
|
||||
styleId = STYLE_COMBO_BOX;
|
||||
trackHover = true;
|
||||
init();
|
||||
}
|
||||
|
||||
|
@ -131,6 +144,8 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
|
|||
//_body.state = State.Parent;
|
||||
//focusable = true;
|
||||
_button.focusable = false;
|
||||
_body.focusable = false;
|
||||
focusable = true;
|
||||
//_body.focusable = true;
|
||||
addChild(_body);
|
||||
addChild(_button);
|
||||
|
@ -198,14 +213,13 @@ class ComboBox : ComboBoxBase {
|
|||
_body.focusable = false;
|
||||
_body.clickable = true;
|
||||
focusable = true;
|
||||
//styleId = "COMBO_BOX";
|
||||
clickable = true;
|
||||
onClickListener = this;
|
||||
}
|
||||
|
||||
override protected Widget createSelectedItemWidget() {
|
||||
TextWidget res = new TextWidget("COMBOBOX_BODY");
|
||||
res.styleId = "COMBO_BOX";
|
||||
TextWidget res = new TextWidget("COMBO_BOX_BODY");
|
||||
res.styleId = STYLE_COMBO_BOX_BODY;
|
||||
res.clickable = true;
|
||||
res.layoutWidth = FILL_PARENT;
|
||||
res.layoutHeight = WRAP_CONTENT;
|
||||
|
@ -264,8 +278,8 @@ class ComboEdit : ComboBox {
|
|||
|
||||
override void init() {
|
||||
super.init();
|
||||
focusable = false;
|
||||
_body.focusable = true;
|
||||
//focusable = false;
|
||||
//_body.focusable = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ private import std.conv : to;
|
|||
/// vertical spacer to fill empty space in vertical layouts
|
||||
class VSpacer : Widget {
|
||||
this() {
|
||||
styleId = "VSPACER";
|
||||
styleId = STYLE_VSPACER;
|
||||
}
|
||||
//override void measure(int parentWidth, int parentHeight) {
|
||||
// measuredContent(parentWidth, parentHeight, 8, 8);
|
||||
|
@ -46,7 +46,7 @@ class VSpacer : Widget {
|
|||
/// horizontal spacer to fill empty space in horizontal layouts
|
||||
class HSpacer : Widget {
|
||||
this() {
|
||||
styleId = "HSPACER";
|
||||
styleId = STYLE_HSPACER;
|
||||
}
|
||||
//override void measure(int parentWidth, int parentHeight) {
|
||||
// measuredContent(parentWidth, parentHeight, 8, 8);
|
||||
|
@ -57,12 +57,12 @@ class HSpacer : Widget {
|
|||
class TextWidget : Widget {
|
||||
this(string ID = null, string textResourceId = null) {
|
||||
super(ID);
|
||||
styleId = "TEXT";
|
||||
styleId = STYLE_TEXT;
|
||||
_text = textResourceId;
|
||||
}
|
||||
this(string ID, dstring rawText) {
|
||||
super(ID);
|
||||
styleId = "TEXT";
|
||||
styleId = STYLE_TEXT;
|
||||
_text = rawText;
|
||||
}
|
||||
protected UIString _text;
|
||||
|
@ -199,7 +199,7 @@ class ImageButton : ImageWidget {
|
|||
/// constructor by id and icon resource id
|
||||
this(string ID = null, string drawableId = null) {
|
||||
super(ID, drawableId);
|
||||
styleId = "BUTTON";
|
||||
styleId = STYLE_BUTTON;
|
||||
_drawableId = drawableId;
|
||||
clickable = true;
|
||||
focusable = true;
|
||||
|
@ -247,10 +247,11 @@ class ImageTextButton : HorizontalLayout {
|
|||
}
|
||||
|
||||
protected void init(string drawableId, UIString caption) {
|
||||
styleId = "BUTTON";
|
||||
styleId = STYLE_BUTTON;
|
||||
_icon = new ImageWidget("icon", drawableId);
|
||||
_icon.styleId = STYLE_BUTTON_IMAGE;
|
||||
_label = new TextWidget("label", caption);
|
||||
_label.styleId = "BUTTON_LABEL";
|
||||
_label.styleId = STYLE_BUTTON_LABEL;
|
||||
_icon.state = State.Parent;
|
||||
_label.state = State.Parent;
|
||||
addChild(_icon);
|
||||
|
@ -285,12 +286,17 @@ class ImageTextButton : HorizontalLayout {
|
|||
class CheckBox : ImageTextButton {
|
||||
this(string ID = null, string textResourceId = null) {
|
||||
super(ID, "btn_check", textResourceId);
|
||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
||||
checkable = true;
|
||||
}
|
||||
this(string ID, dstring 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;
|
||||
}
|
||||
// called to process click and notify listeners
|
||||
|
@ -304,12 +310,17 @@ class CheckBox : ImageTextButton {
|
|||
class RadioButton : ImageTextButton {
|
||||
this(string ID = null, string textResourceId = null) {
|
||||
super(ID, "btn_radio", textResourceId);
|
||||
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
|
||||
checkable = true;
|
||||
}
|
||||
this(string ID, dstring 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;
|
||||
}
|
||||
|
||||
|
@ -351,7 +362,7 @@ class Button : Widget {
|
|||
}
|
||||
|
||||
private void init(UIString label) {
|
||||
styleId = "BUTTON";
|
||||
styleId = STYLE_BUTTON;
|
||||
_text = label;
|
||||
clickable = true;
|
||||
focusable = true;
|
||||
|
@ -397,7 +408,7 @@ class Button : Widget {
|
|||
FontRef font = font();
|
||||
Point sz = font.textSize(text);
|
||||
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 {
|
||||
this(string ID) {
|
||||
super(ID);
|
||||
styleId = "PAGE_SCROLL";
|
||||
styleId = STYLE_PAGE_SCROLL;
|
||||
trackHover = true;
|
||||
clickable = true;
|
||||
}
|
||||
|
@ -511,7 +522,7 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
|||
|
||||
this(string resourceId) {
|
||||
super("SLIDER", resourceId);
|
||||
styleId = "BUTTON_NOMARGINS";
|
||||
styleId = STYLE_BUTTON_NOMARGINS;
|
||||
trackHover = true;
|
||||
}
|
||||
|
||||
|
@ -671,14 +682,14 @@ class ScrollBar : AbstractSlider, OnClickHandler {
|
|||
/// create with ID parameter
|
||||
this(string ID, Orientation orient = Orientation.Vertical) {
|
||||
super(ID);
|
||||
styleId = "SCROLLBAR";
|
||||
styleId = STYLE_SCROLLBAR;
|
||||
_orientation = orient;
|
||||
_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));
|
||||
_pageUp = new PageScrollButton("PAGE_UP");
|
||||
_pageDown = new PageScrollButton("PAGE_DOWN");
|
||||
_btnBack.styleId("SCROLLBAR_BUTTON");
|
||||
_btnForward.styleId("SCROLLBAR_BUTTON");
|
||||
_btnBack.styleId = STYLE_SCROLLBAR_BUTTON;
|
||||
_btnForward.styleId = STYLE_SCROLLBAR_BUTTON;
|
||||
_indicator = new SliderButton(style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL));
|
||||
addChild(_btnBack);
|
||||
addChild(_btnForward);
|
||||
|
|
|
@ -926,6 +926,13 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
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 bool isActionEnabled(const Action action) {
|
||||
switch (action.id) {
|
||||
|
@ -1727,7 +1734,7 @@ class EditLine : EditWidgetBase {
|
|||
_content = new EditableContent(false);
|
||||
_content.contentChangeListeners = this;
|
||||
wantTabs = false;
|
||||
styleId = "EDIT_LINE";
|
||||
styleId = STYLE_EDIT_LINE;
|
||||
text = initialContent;
|
||||
}
|
||||
|
||||
|
@ -1905,7 +1912,7 @@ class EditBox : EditWidgetBase {
|
|||
super(ID, hscrollbarMode, vscrollbarMode);
|
||||
_content = new EditableContent(true); // multiline
|
||||
_content.contentChangeListeners = this;
|
||||
styleId = "EDIT_BOX";
|
||||
styleId = STYLE_EDIT_BOX;
|
||||
text = initialContent;
|
||||
}
|
||||
|
||||
|
|
|
@ -1170,7 +1170,7 @@ class StringGridWidget : StringGridWidgetBase {
|
|||
/// create with ID parameter
|
||||
this(string ID) {
|
||||
super(ID);
|
||||
styleId = "EDIT_BOX";
|
||||
styleId = STYLE_EDIT_BOX;
|
||||
}
|
||||
/// get cell text
|
||||
override dstring cellText(int col, int row) {
|
||||
|
|
|
@ -174,15 +174,20 @@ class LayoutItems {
|
|||
contentSecondarySize = maxItem;
|
||||
else
|
||||
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
|
||||
} else if (totalSize > rc.height) {
|
||||
delta = rc.height - totalSize; // total space to reduce to fit
|
||||
}
|
||||
} else {
|
||||
if (_layoutHeight == WRAP_CONTENT && maxItem < rc.height)
|
||||
contentSecondarySize = maxItem;
|
||||
else
|
||||
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
|
||||
else if (totalSize > rc.width)
|
||||
delta = rc.width - totalSize; // total space to reduce to fit
|
||||
}
|
||||
// calculate resize options and scale
|
||||
bool needForceResize = false;
|
||||
|
@ -194,7 +199,7 @@ class LayoutItems {
|
|||
// need resize of some children
|
||||
needResize = true;
|
||||
// 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
|
||||
if (needForceResize && nonresizableSize + resizableSize > 0)
|
||||
scaleFactor = 10000 * delta / (nonresizableSize + resizableSize);
|
||||
|
@ -467,7 +472,7 @@ class ResizerWidget : Widget {
|
|||
|
||||
|
||||
/// Arranges items either vertically or horizontally
|
||||
class LinearLayout : WidgetGroup {
|
||||
class LinearLayout : WidgetGroupDefaultDrawing {
|
||||
protected Orientation _orientation = Orientation.Vertical;
|
||||
/// returns linear layout orientation (Vertical, Horizontal)
|
||||
@property Orientation orientation() { return _orientation; }
|
||||
|
@ -514,22 +519,6 @@ class LinearLayout : WidgetGroup {
|
|||
applyPadding(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)
|
||||
class FrameLayout : WidgetGroup {
|
||||
class FrameLayout : WidgetGroupDefaultDrawing {
|
||||
/// empty parameter list constructor - for usage by factory
|
||||
this() {
|
||||
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
|
||||
bool showChild(string ID, Visibility otherChildrenVisibility = Visibility.Invisible, bool updateFocus = false) {
|
||||
bool found = false;
|
||||
|
@ -650,7 +622,7 @@ class FrameLayout : WidgetGroup {
|
|||
}
|
||||
|
||||
/// layout children as table with rows and columns
|
||||
class TableLayout : WidgetGroup {
|
||||
class TableLayout : WidgetGroupDefaultDrawing {
|
||||
|
||||
this(string ID = null) {
|
||||
super(ID);
|
||||
|
@ -840,21 +812,4 @@ class TableLayout : WidgetGroup {
|
|||
_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();
|
||||
if (_widget is null) {
|
||||
_widget = new TextWidget("LIST_ITEM");
|
||||
_widget.styleId = "LIST_ITEM";
|
||||
_widget.styleId = STYLE_LIST_ITEM;
|
||||
} else {
|
||||
if (index == _lastItemIndex)
|
||||
return _widget;
|
||||
|
|
|
@ -206,7 +206,7 @@ class MenuItem {
|
|||
}
|
||||
|
||||
/// widget to draw menu item
|
||||
class MenuItemWidget : WidgetGroup {
|
||||
class MenuItemWidget : WidgetGroupDefaultDrawing {
|
||||
protected bool _mainMenu;
|
||||
protected MenuItem _item;
|
||||
protected ImageWidget _icon;
|
||||
|
@ -298,29 +298,11 @@ class MenuItemWidget : WidgetGroup {
|
|||
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) {
|
||||
id="menuitem";
|
||||
_mainMenu = mainMenu;
|
||||
_item = item;
|
||||
styleId = "MENU_ITEM";
|
||||
styleId = STYLE_MENU_ITEM;
|
||||
updateState();
|
||||
string iconId = _item.action.iconId;
|
||||
if (_item.type == MenuItemType.Check)
|
||||
|
@ -330,7 +312,7 @@ class MenuItemWidget : WidgetGroup {
|
|||
// icon
|
||||
if (_item.action && iconId.length) {
|
||||
_icon = new ImageWidget("MENU_ICON", iconId);
|
||||
_icon.styleId = "MENU_ICON";
|
||||
_icon.styleId = STYLE_MENU_ICON;
|
||||
_icon.state = State.Parent;
|
||||
addChild(_icon);
|
||||
}
|
||||
|
@ -352,7 +334,7 @@ class MenuItemWidget : WidgetGroup {
|
|||
}
|
||||
if (acc !is null) {
|
||||
_accel = new TextWidget("MENU_ACCEL");
|
||||
_accel.styleId = "MENU_ACCEL";
|
||||
_accel.styleId = STYLE_MENU_ACCEL;
|
||||
_accel.text = acc;
|
||||
_accel.state = State.Parent;
|
||||
if (_item.isSubmenu && !mainMenu)
|
||||
|
@ -382,13 +364,13 @@ class MenuWidgetBase : ListWidget {
|
|||
_item = item;
|
||||
this.orientation = orientation;
|
||||
id = "popup_menu";
|
||||
styleId = "POPUP_MENU";
|
||||
styleId = STYLE_POPUP_MENU;
|
||||
WidgetListAdapter adapter = new WidgetListAdapter();
|
||||
for (int i=0; i < _item.subitemCount; i++) {
|
||||
MenuItem subitem = _item.subitem(i);
|
||||
MenuItemWidget widget = new MenuItemWidget(subitem, orientation == Orientation.Horizontal);
|
||||
if (orientation == Orientation.Horizontal)
|
||||
widget.styleId = "MAIN_MENU_ITEM";
|
||||
widget.styleId = STYLE_MAIN_MENU_ITEM;
|
||||
widget.parent = this;
|
||||
adapter.widgets.add(widget);
|
||||
}
|
||||
|
@ -650,7 +632,7 @@ class MainMenu : MenuWidgetBase {
|
|||
this(MenuItem item) {
|
||||
super(null, item, Orientation.Horizontal);
|
||||
id = "MAIN_MENU";
|
||||
styleId = "MAIN_MENU";
|
||||
styleId = STYLE_MAIN_MENU;
|
||||
_clickOnButtonDown = true;
|
||||
}
|
||||
|
||||
|
@ -799,7 +781,7 @@ class PopupMenu : MenuWidgetBase {
|
|||
this(MenuItem item, MenuWidgetBase parentMenu = null) {
|
||||
super(parentMenu, item, Orientation.Vertical);
|
||||
id = "POPUP_MENU";
|
||||
styleId = "POPUP_MENU";
|
||||
styleId = STYLE_POPUP_MENU;
|
||||
selectOnHover = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,11 +217,19 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
|
|||
pwidth -= m.left + m.right + p.left + p.right;
|
||||
if (parentHeight != SIZE_UNSPECIFIED)
|
||||
pheight -= m.top + m.bottom + p.top + p.bottom;
|
||||
if (_hscrollbar)
|
||||
if (_hscrollbar) {
|
||||
_hscrollbar.measure(pwidth, pheight);
|
||||
if (_vscrollbar)
|
||||
}
|
||||
if (_vscrollbar) {
|
||||
_vscrollbar.measure(pwidth, pheight);
|
||||
}
|
||||
Point sz = fullContentSize();
|
||||
if (_hscrollbar) {
|
||||
sz.y += _hscrollbar.measuredHeight;
|
||||
}
|
||||
if (_vscrollbar) {
|
||||
sz.x += _vscrollbar.measuredWidth;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
class ScrollWidget : ScrollWidgetBase {
|
||||
protected WidgetGroup _contentWidget;
|
||||
@property WidgetGroup contentWidget() { return _contentWidget; }
|
||||
@property ScrollWidget contentWidget(WidgetGroup newContent) {
|
||||
protected Widget _contentWidget;
|
||||
@property Widget contentWidget() { return _contentWidget; }
|
||||
@property ScrollWidget contentWidget(Widget newContent) {
|
||||
if (_contentWidget) {
|
||||
removeChild(childIndex(_contentWidget));
|
||||
destroy(_contentWidget);
|
||||
|
|
|
@ -25,14 +25,110 @@ private import std.string;
|
|||
private import std.algorithm;
|
||||
|
||||
import dlangui.core.types;
|
||||
import dlangui.graphics.colors;
|
||||
import dlangui.graphics.fonts;
|
||||
import dlangui.graphics.drawbuf;
|
||||
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 uint COLOR_UNSPECIFIED = 0xFFDEADFF;
|
||||
/// transparent color constant
|
||||
immutable uint COLOR_TRANSPARENT = 0xFFFFFFFF;
|
||||
/// unspecified font size constant - to take parent style property value
|
||||
immutable ushort FONT_SIZE_UNSPECIFIED = 0xFFFF;
|
||||
/// 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;
|
||||
/// italic font style constant
|
||||
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
|
||||
immutable uint TEXT_FLAGS_UNSPECIFIED = uint.max;
|
||||
/// use text flags from parent widget
|
||||
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
|
||||
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
|
||||
enum Align : ubyte {
|
||||
/// alignment is not specified
|
||||
|
@ -91,32 +186,6 @@ enum TextFlag : uint {
|
|||
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
|
||||
class Style {
|
||||
protected string _id;
|
||||
|
@ -146,10 +215,13 @@ class Style {
|
|||
protected int _layoutHeight = SIZE_UNSPECIFIED;
|
||||
protected int _layoutWeight = WEIGHT_UNSPECIFIED;
|
||||
|
||||
protected uint[] _focusRectColors;
|
||||
|
||||
protected Style[] _substates;
|
||||
protected Style[] _children;
|
||||
|
||||
protected DrawableAttribute[string] _customDrawables;
|
||||
protected uint[string] _customColors;
|
||||
|
||||
protected FontRef _font;
|
||||
protected DrawableRef _backgroundDrawable;
|
||||
|
@ -226,6 +298,19 @@ class Style {
|
|||
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
|
||||
|
@ -532,6 +617,22 @@ class Style {
|
|||
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) {
|
||||
_padding.left = left;
|
||||
_padding.top = top;
|
||||
|
@ -616,7 +717,7 @@ class Theme : Style {
|
|||
this(string id) {
|
||||
super(this, id);
|
||||
_parentStyle = null;
|
||||
_backgroundColor = 0xFFFFFFFF; // transparent
|
||||
_backgroundColor = COLOR_TRANSPARENT; // transparent
|
||||
_textColor = 0x000000; // black
|
||||
_align = Align.TopLeft;
|
||||
_fontSize = 14; // TODO: from settings or screen properties / DPI
|
||||
|
@ -677,18 +778,32 @@ class Theme : Style {
|
|||
}
|
||||
|
||||
private DrawableRef _emptyDrawable;
|
||||
@property override ref DrawableRef customDrawable(string id) const {
|
||||
override ref DrawableRef customDrawable(string id) const {
|
||||
if (id in _customDrawables)
|
||||
return _customDrawables[id].drawable;
|
||||
return (cast(Theme)this)._emptyDrawable;
|
||||
}
|
||||
|
||||
@property override string customDrawableId(string id) const {
|
||||
override string customDrawableId(string id) const {
|
||||
if (id in _customDrawables)
|
||||
return _customDrawables[id].drawableId;
|
||||
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
|
||||
override Style createSubstyle(string id) {
|
||||
if (id !is null && id in _byId)
|
||||
|
@ -745,14 +860,14 @@ Theme createDefaultTheme() {
|
|||
}
|
||||
//res.fontFace = "Arial Narrow";
|
||||
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);
|
||||
res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
|
||||
res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
|
||||
res.createSubstyle("BUTTON_ICON").alignment(Align.Center);
|
||||
res.createSubstyle("TEXT").setMargins(2,2,2,2).setPadding(1,1,1,1);
|
||||
res.createSubstyle("HSPACER").layoutWidth(FILL_PARENT).minWidth(5).layoutWeight(100);
|
||||
res.createSubstyle("VSPACER").layoutHeight(FILL_PARENT).minHeight(5).layoutWeight(100);
|
||||
res.createSubstyle("BUTTON_NOMARGINS").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(STYLE_BUTTON_TRANSPARENT).backgroundImageId("btn_background_transparent").alignment(Align.Center);
|
||||
res.createSubstyle(STYLE_BUTTON_LABEL).layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
|
||||
res.createSubstyle(STYLE_BUTTON_IMAGE).alignment(Align.Center);
|
||||
res.createSubstyle(STYLE_TEXT).setMargins(2,2,2,2).setPadding(1,1,1,1);
|
||||
res.createSubstyle(STYLE_HSPACER).layoutWidth(FILL_PARENT).minWidth(5).layoutWeight(100);
|
||||
res.createSubstyle(STYLE_VSPACER).layoutHeight(FILL_PARENT).minHeight(5).layoutWeight(100);
|
||||
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, 0).backgroundImageId("btn_default_small_normal_disable");
|
||||
//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_HORIZONTAL, "scrollbar_indicator_horizontal");
|
||||
|
||||
Style scrollbar = res.createSubstyle("SCROLLBAR");
|
||||
Style scrollbar = res.createSubstyle(STYLE_SCROLLBAR);
|
||||
scrollbar.backgroundColor(0xC0808080);
|
||||
Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
|
||||
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
|
||||
Style scrollbarButton = button.createSubstyle(STYLE_SCROLLBAR_BUTTON);
|
||||
Style scrollbarSlider = res.createSubstyle(STYLE_SLIDER);
|
||||
Style scrollbarPage = res.createSubstyle(STYLE_PAGE_SCROLL).backgroundColor(COLOR_TRANSPARENT);
|
||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
||||
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.layoutWidth(FILL_PARENT);
|
||||
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.createState(State.Selected, State.Selected).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.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_normal");
|
||||
//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.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
|
||||
//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.backgroundColor(0xF0F0F0);
|
||||
Style tabWidget = res.createSubstyle("TAB_WIDGET");
|
||||
Style tabWidget = res.createSubstyle(STYLE_TAB_WIDGET);
|
||||
tabWidget.setPadding(3,3,3,3).backgroundColor(0xEEEEEE);
|
||||
//tabWidget.backgroundImageId("frame_blue");
|
||||
//res.dumpStats();
|
||||
|
||||
Style mainMenu = res.createSubstyle("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 menuItem = res.createSubstyle("MENU_ITEM").setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
||||
Style mainMenu = res.createSubstyle(STYLE_MAIN_MENU).backgroundColor(0xEFEFF2).layoutWidth(FILL_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(STYLE_MENU_ITEM).setPadding(4,2,4,2); //.backgroundColor(0xE0E080) ;
|
||||
menuItem.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
|
||||
menuItem.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
||||
menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
||||
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("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("MENU_ACCEL").setMargins(4,2,4,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).textColor(0x80404040);
|
||||
res.createSubstyle(STYLE_MENU_ICON).setMargins(2,2,2,2).alignment(Align.VCenter|Align.Left).createState(State.Enabled,0).alpha(0xA0);
|
||||
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(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(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.Pressed, State.Pressed).backgroundColor(0x4080C000);
|
||||
//transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
|
||||
//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.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)
|
||||
.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)
|
||||
.fontFace("Courier New").fontFamily(FontFamily.MonoSpace).fontSize(16);
|
||||
|
||||
|
@ -858,6 +973,25 @@ Rect decodeRect(string s) {
|
|||
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
|
||||
ubyte decodeAlignment(string s) {
|
||||
ubyte res = 0;
|
||||
|
@ -983,6 +1117,8 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
|||
style.alpha = decodeDimension(elem.tag.attr["alpha"]);
|
||||
if ("textFlags" in elem.tag.attr)
|
||||
style.textFlags = decodeTextFlags(elem.tag.attr["textFlags"]);
|
||||
if ("focusRectColors" in elem.tag.attr)
|
||||
style.focusRectColors = decodeFocusRectColors(elem.tag.attr["focusRectColors"]);
|
||||
foreach(item; elem.elements) {
|
||||
if (allowStates && item.tag.name.equal("state")) {
|
||||
uint stateMask = 0;
|
||||
|
@ -998,6 +1134,13 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
|||
string drawablevalue = attrValue(item, "value");
|
||||
if (drawableid)
|
||||
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;
|
||||
|
@ -1011,7 +1154,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
|
|||
* <?xml version="1.0" encoding="utf-8"?>
|
||||
* <theme id="theme_custom" parent="theme_default">
|
||||
* <style id="BUTTON"
|
||||
* backgroundImageId="btn_default_small"
|
||||
* backgroundImageId="btn_background"
|
||||
* >
|
||||
* </style>
|
||||
* </theme>
|
||||
|
@ -1092,6 +1235,33 @@ Theme loadTheme(string resourceId) {
|
|||
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() {
|
||||
currentTheme = null;
|
||||
}
|
||||
|
|
|
@ -67,14 +67,14 @@ class TabItemWidget : HorizontalLayout {
|
|||
@property TabItem tabItem() { return _item; }
|
||||
@property TabControl tabControl() { return cast(TabControl)parent; }
|
||||
this(TabItem item, bool enableCloseButton = true) {
|
||||
styleId = "TAB_UP_BUTTON";
|
||||
styleId = STYLE_TAB_UP_BUTTON;
|
||||
_enableCloseButton = enableCloseButton;
|
||||
_icon = new ImageWidget();
|
||||
_label = new TextWidget();
|
||||
_label.styleId = "TAB_UP_BUTTON_TEXT";
|
||||
_label.styleId = STYLE_TAB_UP_BUTTON_TEXT;
|
||||
_label.state = State.Parent;
|
||||
_closeButton = new ImageButton("CLOSE");
|
||||
_closeButton.styleId = "BUTTON_TRANSPARENT";
|
||||
_closeButton.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||
_closeButton.drawableId = "close";
|
||||
_closeButton.trackHover = true;
|
||||
_closeButton.onClickListener = &onClick;
|
||||
|
@ -167,7 +167,7 @@ class TabItemList {
|
|||
}
|
||||
|
||||
/// tab header - tab labels, with optional More button
|
||||
class TabControl : WidgetGroup {
|
||||
class TabControl : WidgetGroupDefaultDrawing {
|
||||
protected TabItemList _items;
|
||||
protected ImageButton _moreButton;
|
||||
protected bool _enableCloseButton;
|
||||
|
@ -186,11 +186,11 @@ class TabControl : WidgetGroup {
|
|||
super(ID);
|
||||
_items = new TabItemList();
|
||||
_moreButton = new ImageButton("MORE", "tab_more");
|
||||
_moreButton.styleId = "BUTTON_TRANSPARENT";
|
||||
_moreButton.styleId = STYLE_BUTTON_TRANSPARENT;
|
||||
_moreButton.onClickListener = &onClick;
|
||||
_moreButton.margins(Rect(3,3,3,6));
|
||||
_enableCloseButton = true;
|
||||
styleId = "TAB_UP";
|
||||
styleId = STYLE_TAB_UP;
|
||||
addChild(_moreButton); // first child is always MORE button, the rest corresponds to tab list
|
||||
}
|
||||
/// returns tab count
|
||||
|
@ -338,24 +338,6 @@ class TabControl : WidgetGroup {
|
|||
}
|
||||
//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;
|
||||
|
||||
|
@ -388,7 +370,7 @@ class TabHost : FrameLayout, TabHandler {
|
|||
_tabControl = tabControl;
|
||||
if (_tabControl !is null)
|
||||
_tabControl.onTabChangedListener = &onTabChanged;
|
||||
styleId = "TAB_HOST";
|
||||
styleId = STYLE_TAB_HOST;
|
||||
}
|
||||
protected TabControl _tabControl;
|
||||
/// get currently set control widget
|
||||
|
@ -478,7 +460,7 @@ class TabWidget : VerticalLayout, TabHandler {
|
|||
_tabControl = new TabControl("TAB_CONTROL");
|
||||
_tabHost = new TabHost("TAB_HOST", _tabControl);
|
||||
_tabControl.onTabChangedListener.connect(this);
|
||||
styleId = "TAB_WIDGET";
|
||||
styleId = STYLE_TAB_WIDGET;
|
||||
addChild(_tabControl);
|
||||
addChild(_tabHost);
|
||||
}
|
||||
|
|
|
@ -122,6 +122,10 @@ class TreeItem {
|
|||
p = p._parent;
|
||||
return cast(TreeItems)p;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_children.clear();
|
||||
}
|
||||
|
||||
@property TreeItem parent() { return _parent; }
|
||||
@property protected TreeItem parent(TreeItem p) { _parent = p; return this; }
|
||||
|
@ -197,6 +201,29 @@ class TreeItem {
|
|||
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
|
||||
@property bool hasChildren() { return childCount > 0; }
|
||||
|
||||
|
@ -440,7 +467,7 @@ class TreeItemWidget : HorizontalLayout {
|
|||
|
||||
this(TreeItem item) {
|
||||
super(item.id);
|
||||
styleId = "TREE_ITEM";
|
||||
styleId = STYLE_TREE_ITEM;
|
||||
|
||||
clickable = true;
|
||||
focusable = true;
|
||||
|
@ -458,7 +485,7 @@ class TreeItemWidget : HorizontalLayout {
|
|||
_tab.maxWidth = w;
|
||||
if (_item.hasChildren) {
|
||||
_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.trackHover = true;
|
||||
//_expander.setState(State.Parent);
|
||||
|
@ -484,11 +511,11 @@ class TreeItemWidget : HorizontalLayout {
|
|||
};
|
||||
if (_item.iconRes.length > 0) {
|
||||
_icon = new ImageWidget("icon", _item.iconRes);
|
||||
_icon.styleId = "TREE_ITEM_ICON";
|
||||
_icon.styleId = STYLE_TREE_ITEM_ICON;
|
||||
_icon.setState(State.Parent);
|
||||
}
|
||||
_label = new TextWidget("label", _item.text);
|
||||
_label.styleId = "TREE_ITEM_LABEL";
|
||||
_label.styleId = STYLE_TREE_ITEM_LABEL;
|
||||
_label.setState(State.Parent);
|
||||
// append children
|
||||
addChild(_tab);
|
||||
|
@ -643,7 +670,7 @@ class TreeWidgetBase : ScrollWidget, OnTreeContentChangeListener, OnTreeStateCh
|
|||
super.layout(rc);
|
||||
}
|
||||
|
||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
return;
|
||||
|
|
|
@ -38,6 +38,7 @@ module dlangui.widgets.widget;
|
|||
public import dlangui.core.types;
|
||||
public import dlangui.core.events;
|
||||
public import dlangui.core.i18n;
|
||||
public import dlangui.core.collections;
|
||||
public import dlangui.widgets.styles;
|
||||
|
||||
public import dlangui.graphics.drawbuf;
|
||||
|
@ -315,8 +316,9 @@ class Widget {
|
|||
requestLayout();
|
||||
return this;
|
||||
}
|
||||
immutable static int FOCUS_RECT_PADDING = 2;
|
||||
/// 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
|
||||
Rect p = style.padding;
|
||||
DrawableRef d = backgroundDrawable;
|
||||
|
@ -331,6 +333,10 @@ class Widget {
|
|||
if (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;
|
||||
}
|
||||
/// set padding for widget - override one from style
|
||||
|
@ -358,7 +364,12 @@ class Widget {
|
|||
ownStyle.backgroundImageId = imageId;
|
||||
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
|
||||
@property DrawableRef backgroundDrawable() const {
|
||||
return stateStyle.backgroundDrawable;
|
||||
|
@ -588,10 +599,10 @@ class Widget {
|
|||
|
||||
protected bool _focusable;
|
||||
/// 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 bool focused() {
|
||||
@property bool focused() const {
|
||||
return (window !is null && window.focusedWidget is this && (state & State.Focused));
|
||||
}
|
||||
|
||||
|
@ -694,7 +705,7 @@ class Widget {
|
|||
applyPadding(rc);
|
||||
if (!rc.intersects(clipRect))
|
||||
return; // out of clip rectangle
|
||||
if (focusable) {
|
||||
if (canFocus) {
|
||||
TabOrderInfo item = new TabOrderInfo(this, rc);
|
||||
results ~= item;
|
||||
return;
|
||||
|
@ -839,9 +850,9 @@ class Widget {
|
|||
return parent.visible;
|
||||
}
|
||||
|
||||
/// returns true if widget is focusable and visible
|
||||
/// returns true if widget is focusable and visible and enabled
|
||||
@property bool canFocus() {
|
||||
return focusable && visible;
|
||||
return focusable && visible && enabled;
|
||||
}
|
||||
|
||||
/// 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
|
||||
int dx = m.left + m.right + p.left + p.right + contentWidth;
|
||||
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
|
||||
int minw = minWidth;
|
||||
int maxw = maxWidth;
|
||||
int minh = minHeight;
|
||||
int maxh = maxHeight;
|
||||
if (dx < minw)
|
||||
if (minw != SIZE_UNSPECIFIED && dx < minw)
|
||||
dx = minw;
|
||||
if (dy < minh)
|
||||
if (minh != SIZE_UNSPECIFIED && dy < minh)
|
||||
dy = minh;
|
||||
if (maxw != SIZE_UNSPECIFIED && dx > maxw)
|
||||
dx = maxw;
|
||||
if (maxh != SIZE_UNSPECIFIED && 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
|
||||
if (parentWidth != SIZE_UNSPECIFIED && dx > parentWidth)
|
||||
dx = parentWidth;
|
||||
|
@ -1095,6 +1118,14 @@ class Widget {
|
|||
_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
|
||||
void onDraw(DrawBuf buf) {
|
||||
if (visibility != Visibility.Visible)
|
||||
|
@ -1107,6 +1138,10 @@ class Widget {
|
|||
bg.drawTo(buf, rc, state);
|
||||
}
|
||||
applyPadding(rc);
|
||||
if (state & State.Focused) {
|
||||
rc.expand(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
|
||||
drawFocusRect(buf, rc);
|
||||
}
|
||||
_needDraw = false;
|
||||
}
|
||||
|
||||
|
@ -1229,15 +1264,15 @@ class 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
|
||||
@property Widget parent(Widget parent) { _parent = parent; return this; }
|
||||
/// returns window (if widget or its parent is attached to window)
|
||||
@property Window window() {
|
||||
Widget p = this;
|
||||
@property Window window() const {
|
||||
Widget p = cast(Widget)this;
|
||||
while (p !is null) {
|
||||
if (p._window !is null)
|
||||
return p._window;
|
||||
return cast(Window)p._window;
|
||||
p = p.parent;
|
||||
}
|
||||
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. */
|
||||
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;
|
||||
|
||||
/// Helper to handle animation progress
|
||||
|
|