1
0
Fork 0

Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/fgdata into next

This commit is contained in:
Erik Hofman 2023-01-04 08:57:53 +01:00
commit 643e697ec0
8 changed files with 457 additions and 6 deletions

View file

@ -185,6 +185,22 @@ var Element = {
}
return center;
},
# Set size in pixels
# Use either with x, y size:
# e.setSize(<x>, <y>)
# or with a vector containing x, y:
# e.setSize([<x>, <y>])
setSize: func {
if (size(arg) == 1) {
var (x, y) = arg[0];
} else {
var (x, y) = arg;
}
var (sx, sy) = me.getScale();
var (curx, cury) = me.getSize();
me.setScale(x / (curx / sy), y / (cury / sy));
},
#return vector [sx, sy] with dimensions of bounding box
getSize: func {

View file

@ -37,13 +37,16 @@ loadWidget("Button");
loadWidget("CheckBox");
loadWidget("Label");
loadWidget("LineEdit");
loadWidget("PropertyWidgets");
loadWidget("ScrollArea");
loadWidget("Rule");
loadWidget("Slider");
loadWidget("TabWidget");
# standard dialogs
loadDialog("InputDialog");
loadDialog("MessageBox");
loadDialog("WidgetsFactoryDialog");
var style = DefaultStyle.new("AmbianceClassic", "Humanity");
var WindowButton = {
@ -307,6 +310,7 @@ var Window = {
{
me._ghost.show();
me.raise();
me._canvas.update();
},
# Hide / show the window based on whether it's currently visible
toggle: func()

View file

@ -0,0 +1,70 @@
var WidgetsFactoryDialog = {
new: func {
var m = {
parents: [WidgetsFactoryDialog, canvas.Window.new([500, 500], "dialog")]
};
m.setBool("resize", 1);
m.root = m.getCanvas(1)
.set("background", style.getColor("bg_color"))
.createGroup();
m.vbox = VBoxLayout.new();
#m.vbox.setContentsMargin(10);
m.setLayout(m.vbox);
m.tabs = gui.widgets.TabWidget.new(m.root, style, {});
m.tabsContent = m.tabs.getContent();
m.vbox.addItem(m.tabs);
m.tab_1 = VBoxLayout.new();
m.tabs.addTab("tab-1", "Tab 1", m.tab_1);
m.label = gui.widgets.Label.new(m.tabsContent, style, {})
.setText("A label")
.setBackground("#ffaaaa");
m.tab_1.addItem(m.label);
m.checkbox_left = gui.widgets.CheckBox.new(m.tabsContent, style, {"label-position": "right"})
.setText("Wanna check something ?");
m.tab_1.addItem(m.checkbox_left);
m.checkbox_right = gui.widgets.CheckBox.new(m.tabsContent, style, {"label-position": "right"})
.setText("Checkbox with text on the right side");
m.tab_1.addItem(m.checkbox_right);
m.property_checkbox = gui.widgets.PropertyCheckBox.new(props.globals.getNode("/controls/lighting/nav-lights"), m.tabsContent, style, {})
.setText("Nav lights");
m.tab_1.addItem(m.property_checkbox);
m.tab_2 = VBoxLayout.new();
m.tabs.addTab("tab-2", "Tab 2", m.tab_2);
m.button = gui.widgets.Button.new(m.tabsContent, style, {})
.setText("A button")
.listen("clicked", func {
InputDialog.getText("You clicked the button …", "Enter some text:", func (button, text) {
MessageBox.information("You clicked the button …", "… and entered '" ~ (text != nil ? text : "nothing") ~ "' !");
});
});
m.tab_2.addItem(m.button);
m.image = gui.widgets.Label.new(m.tabsContent, style, {})
.setImage("Textures/Splash1.png")
.setFixedSize(128, 128);
m.tab_2.addItem(m.image);
# XXX: setVisible(0) must be called AFTER adding the widget to the layout
# doing that before layout.addItem causes FG to crash with a SIGSEGV
# see https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/CABg8F9Rb87Fy%252B2ppXjJouYcZH9xyiQxts-jkdrPq0GK_Ymq-6w%2540mail.gmail.com/
m.image.setVisible(0);
m.checkable_button = gui.widgets.Button.new(m.tabsContent, style, {})
.setCheckable(1)
.setChecked(0)
.setText("Checkable button")
.listen("toggled", func (e) {
m.image.setVisible(int(e.detail.checked));
});
m.tab_2.addItem(m.checkable_button);
return m;
},
del: func {
me.property_checkbox.del();
}
};

View file

@ -126,7 +126,7 @@ DefaultStyle.widgets.checkbox = {
{
if (me._label_position == "left") {
me._label.setTranslation(3, int((h / 2) + 1));
me._icon.setTranslation(me._label.maxWidth() + 6, int((h - 18) / 2));
me._icon.setTranslation(w - 24, int((h - 18) / 2));
} else {
me._icon.setTranslation(3, int((h - 18) / 2));
me._label.setTranslation(24, int(h / 2) + 1);
@ -458,6 +458,88 @@ DefaultStyle.widgets["scroll-area"] = {
}
};
DefaultStyle.widgets["tab-widget"] = {
tabBarHeight: 30,
new: func(parent, cfg) {
me._root = parent.createChild("group", "tab-widget");
me.bg = me._root.createChild("path", "background")
.set("fill", "#e0e0e0");
me.tabBar = me._root.createChild("group", "tab-widget-tabbar");
me.content = me._root.createChild("group", "tab-widget-content");
},
update: func(model) {
me.bg.set("fill", me._style.getColor("bg_color"));
me.tabBar.update();
me.content.update();
},
setSize: func(model, w, h) {
me.bg.reset().rect(0, w, h, 0);
me.tabBar.set("clip", sprintf("rect(0, %d, %d, 0)", w, me.tabBarHeight));
me.content.setTranslation(0, me.tabBarHeight);
me.content.set("clip", sprintf("rect(0, %d, %d, 0)", w, h));
},
};
# Tab button for the tab widget
DefaultStyle.widgets["tab-widget-tab-button"] = {
new: func(parent, cfg) {
me._root = parent.createChild("group", "tab-widget-tab-button");
me._bg = me._root.createChild("path")
.set("fill", me._style.getColor("tab_widget_tab_button_bg_focused"))
.set("stroke", me._style.getColor("tab_widget_tab_button_border"))
.set("stroke-width", 1);
me._selected_indicator = me._root.createChild("path")
.set("stroke", me._style.getColor("tab_widget_tab_button_selected_indicator"))
.set("stroke-width", 3);
me._label = me._root.createChild("text")
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "center-baseline");
},
setSize: func(model, w, h) {
me._bg.reset().rect(3, 0, w - 6, h);
me._selected_indicator.reset().moveTo(3, h).horiz(w - 6);
},
setText: func(model, text) {
me._label.setText(text);
var min_width = math.max(80, me._label.maxWidth() + 16);
model.setLayoutMinimumSize([min_width, 30]);
model.setLayoutSizeHint([min_width, 30]);
return me;
},
update: func(model) {
var backdrop = !model._windowFocus();
var (w, h) = model._size;
me._label.setTranslation(w / 2, h / 2 + 5);
var bg_color_name = "tab_widget_tab_button_bg_focused";
if (backdrop) {
bg_color_name = "tab_widget_tab_button_bg_unfocused";
} else if (model._selected) {
bg_color_name = "tab_widget_tab_button_bg_selected";
} else if (model._hover) {
bg_color_name = "tab_widget_tab_button_bg_hovered";
}
me._bg.set("fill", me._style.getColor(bg_color_name));
me._selected_indicator.setVisible(model._selected);
if (backdrop) {
me._label.set("fill", me._style.getColor("backdrop_fg_color"));
} else {
me._label.set("fill", me._style.getColor("fg_color"));
}
}
};
# A horizontal or vertical rule line
# possibly with a text label embedded
DefaultStyle.widgets.rule = {

View file

@ -0,0 +1,33 @@
# PropertyWidgets.nas - subclassed canvas widgets that are synced with a property node
# SPDX-FileCopyrightText: (C) 2022 Frederic Croix <thefgfseagle@gmail.com>
# SPDX-License-Identifier: GPL-2.0-or-later
gui.widgets.PropertyCheckBox = {
new: func(node, parent, style, cfg) {
if (!isa(node, props.Node)) {
node = props.globals.getNode(node, 1);
}
var m = gui.widgets.CheckBox.new(parent, style, cfg);
m._checkable = 1;
m._node = node;
append(m.parents, gui.widgets.PropertyCheckBox);
m.setChecked(m._node.getBoolValue());
m.listen("toggled", func(e) {
m._node.setBoolValue(int(e.detail.checked));
});
m._listener = setlistener(m._node, func(n) {
m.setChecked(n.getBoolValue());
}, 1, 0);
return m;
},
del: func {
removelistener(me._listener);
},
};

View file

@ -0,0 +1,207 @@
# TabWidget.nas - widget with a tabs bar and a content area which always displays
# exactly one of its tabs
# SPDX-FileCopyrightText: (C) 2022 Frederic Croix <thefgfseagle@gmail.com>
# SPDX-License-Identifier: GPL-2.0-or-later
# Usage example
# var window = canvas.Window.new([300, 300], "dialog");
# var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));
# var root = myCanvas.createGroup();
# var vbox = canvas.VBoxLayout.new();
# myCanvas.setLayout(vbox);
#
# var tabs = canvas.gui.widgets.TabWidget.new(root, canvas.style, {});
# var tabsContent = tabs.getContent();
# vbox.addItem(tabs);
#
# var tab1 = canvas.VBoxLayout.new();
# var image1 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setImage("Textures/Splash1.png")
# .setFixedSize(128, 128);
# tab1.addItem(image1);
# var text1 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setText("Texture 1");
# tab1.addItem(text1);
# tabs.addTab("tab1", "Texture 1", tab1);
#
# var tab2 = canvas.VBoxLayout.new();
# var image2 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setImage("Textures/Splash2.png")
# .setFixedSize(128, 128);
# tab2.addItem(image2);
# var text2 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setText("Texture 2");
# tab2.addItem(text2);
# tabs.addTab("tab2", "Texture 2", tab2);
#
# var tab3 = canvas.VBoxLayout.new();
# var image3 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setImage("Textures/Splash3.png")
# .setFixedSize(128, 128);
# tab3.addItem(image3);
# var text3 = canvas.gui.widgets.Label.new(tabsContent, canvas.style, {})
# .setText("Texture 3");
# tab3.addItem(text3);
# tabs.addTab("tab3", "Texture 3", tab3);
gui.widgets.TabWidgetTabButton = {
new: func(parent, style, cfg) {
var cfg = Config.new(cfg);
var m = gui.Widget.new(gui.widgets.TabWidgetTabButton);
m._focus_policy = m.StrongFocus;
m._selected = 0;
m._setView(style.createWidget(parent, "tab-widget-tab-button", cfg));
return m;
},
setText: func(text) {
me._view.setText(me, text);
return me;
},
setSelected: func(selected = 1) {
if (me._selected == selected) {
return me;
}
me._selected = selected;
me._trigger("toggled", {selected: selected});
me._onStateChange();
me._view.update(me);
return me;
},
_setView: func(view) {
call(gui.Widget._setView, [view], me);
var el = view._root;
#el.addEventListener("mousedown", func me.dragStart());
#el.addEventListener("mouseup", func me.dragStop());
el.addEventListener("click", func me.setSelected());
el.addEventListener("drag", func(e) { e.stopPropagation() });
#el.addEventListener("drag", me.drag);
}
};
gui.widgets.TabWidget = {
new: func(parent, style, cfg) {
var m = gui.Widget.new(gui.widgets.TabWidget);
m._cfg = Config.new(cfg);
m._focus_policy = m.NoFocus;
m._setView(style.createWidget(parent, "tab-widget", m._cfg));
m._layout = VBoxLayout.new();
m._layout.setCanvas(m._view._root.getCanvas());
m._tabBar = HBoxLayout.new();
m._layout.addItem(m._tabBar);
m._currentTab = nil;
m._currentTabId = nil;
m._tabs = {};
m._tabButtons = {};
m.setLayoutMinimumSize([50, 30]);
m.setLayoutSizeHint([100, 30]);
return m;
},
getContent: func {
return me._view.content;
},
hasTab: func(id) {
return me._tabs[id] != nil;
},
getTab: func(id) {
if (!me.hasTab(id)) {
die("tab with id '" ~ id ~ "' does not exist");
}
return me._tabs[id];
},
addTab: func(id, label, widget) {
if (me.hasTab(id)) {
die("cannot add multiple tabs with the same id: " ~ id);
}
me._tabButtons[id] = gui.widgets.TabWidgetTabButton.new(me._view.tabBar, canvas.style, {})
.setText(label)
.listen("toggled", func (e) {
if (e.detail.selected and id != me._currentTabId) {
me.setCurrentTab(id);
}
});
me._tabBar.addItem(me._tabButtons[id]);
me._tabs[id] = widget;
me._layout.addItem(widget);
me.setCurrentTab(keys(me._tabs)[0]);
return me;
},
removeTab: func(id) {
if (!me.hasTab(id)) {
die("tab with id '" ~ id ~ "' does not exist");
}
me._tabs[id].setVisible(0);
me._layout.removeItem(me._tabs[id]);
delete(me._tabs, id);
me._tabBar.removeItem(me._tabButtons[id]);
delete(me._tabButtons, id);
if (size(keys(me._tabs)) > 0) {
me.setCurrentTab(keys(me._tabs)[-1]);
}
return me;
},
setCurrentTab: func(id) {
if (!me.hasTab(id)) {
die("tab with id '" ~ id ~ "' does not exist");
}
if (me._currentTabId) {
me._tabButtons[me._currentTabId].setSelected(0);
}
me._tabButtons[id].setSelected();
foreach (var tabid; keys(me._tabs)) {
me._tabs[tabid].setVisible(0);
}
me._tabs[id].setVisible(1);
me._currentTabId = id;
me._currentTab = me._tabs[id];
return me.update();
},
setSize: func {
if (size(arg) == 1) {
var arg = arg[0];
}
var (x, y) = arg;
me._size = [x, y];
return me.update();
},
# Needs to be called when the size of the content changes.
update: func() {
if(me._layout.getParent() == nil) {
me._layout.setParent(me);
}
me._tabBar.setGeometry([0, 0, me._size[0], me._view.tabBarHeight]);
if (me._currentTab) {
me._currentTab.setGeometry([0, me._view.tabBarHeight, me._size[0], me._size[1] - me._view.tabBarHeight]);
}
me._view.setSize(me, me._size[0], me._size[1]);
me._view.update(me);
return me;
},
};

View file

@ -245,6 +245,13 @@
<script>canvas.MapStructure_selfTest();</script>
</binding>
</button>
<button>
<legend>Canvas widgets factory</legend>
<binding>
<command>nasal</command>
<script>canvas.WidgetsFactoryDialog.new();</script>
</binding>
</button>
</group>
<group>

View file

@ -1,5 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<!--
<folders>
@ -8,7 +7,6 @@
</folders>
-->
<colors>
<!-- Window decoration colors -->
<title>
<red type="float">0.275</red>
@ -95,7 +93,41 @@
<green type="float">0.89</green>
<blue type="float">0.89</blue>
</button_bg_color_insensitive>
<tab_widget_tab_button_border>
<red type="float">0.905</red>
<green type="float">0.897</green>
<blue type="float">0.885</blue>
</tab_widget_tab_button_border>
<tab_widget_tab_button_selected_indicator>
<red type="float">0.11</red>
<green type="float">0.42</green>
<blue type="float">0.8</blue>
</tab_widget_tab_button_selected_indicator>
<tab_widget_tab_button_bg_focused>
<red type="float">0.86</red>
<green type="float">0.855</green>
<blue type="float">0.85</blue>
</tab_widget_tab_button_bg_focused>
<tab_widget_tab_button_bg_unfocused>
<red type="float">0.9</red>
<green type="float">0.895</green>
<blue type="float">0.89</blue>
</tab_widget_tab_button_bg_unfocused>
<tab_widget_tab_button_bg_hovered>
<red type="float">0.93</red>
<green type="float">0.925</green>
<blue type="float">0.92</blue>
</tab_widget_tab_button_bg_hovered>
<tab_widget_tab_button_bg_selected>
<red type="float">0.96</red>
<green type="float">0.955</green>
<blue type="float">0.95</blue>
</tab_widget_tab_button_bg_selected>
</colors>
</PropertyList>