1
0
Fork 0

Implemented canvas radio button

This commit is contained in:
TheFGFSEagle 2023-01-21 23:48:44 +01:00 committed by James Turner
parent f569a5ac29
commit 7dd431cbbd
6 changed files with 237 additions and 69 deletions

View file

@ -46,6 +46,7 @@ loadWidget("MenuBar");
loadWidget("PropertyTree");
loadWidget("PropertyWidgets");
loadWidget("ScrollArea");
loadWidget("RadioButton");
loadWidget("Rule");
loadWidget("Slider");
loadWidget("TabWidget");

View file

@ -11,7 +11,6 @@ var WidgetsFactoryDialog = {
.set("background", style.getColor("bg_color"))
.createGroup();
m.vbox = VBoxLayout.new();
#m.vbox.setContentsMargin(10);
m.window.setLayout(m.vbox);
m.menubar = canvas.gui.widgets.MenuBar.new(m.root, canvas.style, {});
@ -22,12 +21,18 @@ var WidgetsFactoryDialog = {
tabsMenu.createItem(text: "Select first tab", cb: func m.tabs.setCurrentTab("tab-1"));
tabsMenu.createItem(text: "Select second tab", cb: func m.tabs.setCurrentTab("tab-2"));
m.menubar.createMenu("Widgets")
.createItem(text: "Benchmark label", cb: func {
m.benchmark_widget(canvas.gui.widgets.Label, func(w, i) {
w.setText("Label " ~ i);
});
});
var widgetsMenu = m.menubar.createMenu("Widgets");
widgetsMenu.createItem(text: "Benchmark label", cb: func {
m.benchmark_widget(canvas.gui.widgets.Label, func(w, i) {
w.setText("Label " ~ i);
});
});
widgetsMenu.createItem(text: "Benchmark radio button", cb: func {
m.benchmark_radio_button(func(w, i) {
w.setText("Radio button " ~ i);
});
});
m.vbox.addItem(m.menubar);
m.tabs = gui.widgets.TabWidget.new(m.root, style, {});
@ -45,11 +50,11 @@ var WidgetsFactoryDialog = {
r.setText("Checkboxes!");
m.tab_1.addItem(r);
m.checkbox_left = gui.widgets.CheckBox.new(m.tabsContent, style, {"label-position": "right"})
m.checkbox_left = gui.widgets.CheckBox.new(m.tabsContent, style, {})
.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.checkbox_right = gui.widgets.CheckBox.new(m.tabsContent, style, {"label-position": "left"})
.setText("Checkbox with text on the left 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");
@ -57,6 +62,19 @@ var WidgetsFactoryDialog = {
var r2 = gui.widgets.HorizontalRule.new(m.tabsContent, style, {});
m.tab_1.addItem(r2);
m.radio1 = gui.widgets.RadioButton.new(m.tabsContent)
.setText("Radio button 1");
m.tab_1.addItem(m.radio1);
m.radio2 = gui.widgets.RadioButton.new(parent: m.tabsContent, cfg: {parentRadio: m.radio1})
.setText("Radio button 2");
m.tab_1.addItem(m.radio2);
m.radio3 = gui.widgets.RadioButton.new(parent: m.tabsContent, cfg: {parentRadio: m.radio1})
.setText("Radio button 3");
m.tab_1.addItem(m.radio3);
m.radio4 = gui.widgets.RadioButton.new(parent: m.tabsContent, cfg: {parentRadio: m.radio1})
.setText("Radio button 4");
m.tab_1.addItem(m.radio4);
m.tab_2 = HBoxLayout.new();
m.tabs.addTab("tab-2", "Tab 2", m.tab_2);
@ -145,6 +163,7 @@ var WidgetsFactoryDialog = {
m.benchmark_tab_scroll = canvas.gui.widgets.ScrollArea.new(m.tabsContent, canvas.style, {});
m.benchmark_tab_scroll.setSizeHint([m.list._MAX_SIZE, m.list._MAX_SIZE]);
m.benchmark_tab_scroll_layout = VBoxLayout.new();
m.benchmark_tab_scroll_layout.setSpacing(0);
m.benchmark_tab_scroll.setLayout(m.benchmark_tab_scroll_layout);
m.benchmark_tab.addItem(m.benchmark_tab_scroll);
m.benchmark_statistics = canvas.gui.widgets.Label.new(m.tabsContent, canvas.style, {});
@ -185,6 +204,21 @@ var WidgetsFactoryDialog = {
me.benchmark_statistics.setText("Took " ~ time ~ " seconds to add " ~ amount ~ " widgets.");
},
benchmark_radio_button: func(proc_func=nil, amount=50) {
var start = systime();
me.benchmark_tab_scroll_layout.clear();
var r = canvas.gui.widgets.RadioButton.new(me.benchmark_tab_scroll.getContent());
for (var i = 1; i < amount; i += 1) {
var w = canvas.gui.widgets.RadioButton.new(me.benchmark_tab_scroll.getContent(), canvas.style, {parentRadio: r});
if (proc_func != nil) {
proc_func(w, i);
}
me.benchmark_tab_scroll_layout.addItem(w);
}
var time = systime() - start;
me.benchmark_statistics.setText("Took " ~ time ~ " seconds to add " ~ amount ~ " widgets.");
},
del: func {
me.property_checkbox.del();
me.window.del();

View file

@ -176,6 +176,73 @@ DefaultStyle.widgets.checkbox = {
}
};
# A checkbox
DefaultStyle.widgets["radio-button"] = {
new: func(parent, cfg) {
me._root = parent.createChild("group", "radio-button");
me._bg = me._root.createChild("path");
me._icon = me._root.createChild("group", "radio-button-icon");
me._icon_background = me._icon.createChild("path", "radio-button-icon-border")
.circle(8.5, 9, 9);
me._icon_selected_indicator = me._icon.createChild("path", "radio-button-icon-selected-indicator")
.circle(6, 9, 9)
.set("stroke-width", 5);
me._icon_border = me._icon.createChild("path", "radio-button-icon-border")
.circle(8, 9, 9)
.set("stroke-width", 1);
me._label = me._root.createChild("text")
.set("font", "LiberationFonts/LiberationSans-Regular.ttf")
.set("character-size", 14)
.set("alignment", "left-center");
},
setSize: func(model, w, h) {
me._bg.reset().rect(0, 0, w, h);
me._icon.setTranslation(3, int((h - 18) / 2));
me._label.setTranslation(24, int(h / 2) + 1);
return me;
},
setText: func(model, text) {
me._label.setText(text);
var min_width = me._label.maxWidth() + 3 + 24;
model.setLayoutMinimumSize([min_width, 24]);
model.setLayoutSizeHint([min_width, 24]);
return me;
},
update: func(model) {
var backdrop = !model._windowFocus();
me._bg.set("fill", me._style.getColor("radio_button_bg_color" ~ (model._hover ? "_hovered" : "")));
me._icon_border.set("stroke", me._style.getColor("radio_button_selected_indicator_border_color"));
if (backdrop) {
me._label.set("fill", me._style.getColor("backdrop_fg_color"));
} else {
me._label.set("fill", me._style.getColor("fg_color"));
}
if (model._checked) {
me._icon_selected_indicator.show();
} else {
me._icon_selected_indicator.hide();
}
if (model._enabled) {
if (model._hover) {
me._icon_background.set("fill", me._style.getColor("radio_button_selected_indicator_bg_color_hovered"));
} else {
me._icon_background.set("fill", me._style.getColor("radio_button_selected_indicator_bg_color"));
}
me._icon_selected_indicator.set("stroke", me._style.getColor("radio_button_selected_indicator_color"));
} else {
me._icon_background.set("fill", me._style.getColor("radio_button_selected_indicator_bg_color_disabled"));
me._icon_selected_indicator.set("stroke", me._style.getColor("radio_button_selected_indicator_color_disabled"));
}
}
};
# A label
DefaultStyle.widgets.label = {
new: func(parent, cfg)

View file

@ -5,17 +5,17 @@
gui.widgets.Button = {
new: func(parent, style, cfg)
{
var cfg = Config.new(cfg);
var m = gui.Widget.new(gui.widgets.Button);
m._cfg = Config.new(cfg);
m._focus_policy = m.StrongFocus;
m._down = 0;
m._checkable = 0;
m._flat = cfg.get("flat", 0);
m._isDefault = cfg.get("default", 0);
m._destructive = cfg.get("destructive", 0);
m._flat = m._cfg.get("flat", 0);
m._isDefault = m._cfg.get("default", 0);
m._destructive = m._cfg.get("destructive", 0);
if( style != nil and !m._flat )
m._setView( style.createWidget(parent, cfg.get("type", "button"), cfg) );
m._setView( style.createWidget(parent, m._cfg.get("type", "button"), m._cfg) );
return m;
},

View file

@ -1,95 +1,113 @@
# RadioButton.nas : radio button, and group helper
# to manage updating checked state conherently
# SPDX-FileCopyrightText: (C) 2022 James Turner <james@flightgear.org>
# SPDX-FileCopyrightText: (C) 2022 James Turner <james@flightgear.org>, Frederic Croix <thefgfseagle@gmail.com>
# SPDX-License-Identifier: GPL-2.0-or-later
gui.widgets.RadioButton = {
new: func(parent, style, cfg)
{
cfg["type"] = "radio";
var m = gui.widgets.Button.new(parent, style, cfg);
m._checkable = 1;
new: func(parent, style = nil, cfg = nil) {
var m = gui.Widget.new(gui.widgets.RadioButton);
style = style or canvas.style;
m._cfg = Config.new(cfg or {});
m._focus_policy = m.StrongFocus;
m._checked = 0;
m.radioGroup = nil;
append(m.parents, gui.widgets.RadioButton);
m._setView( style.createWidget(parent, m._cfg.get("type", "radio-button"), m._cfg) );
if (contains(pr, "radioGroup") {
pr.radioGroup.addRadio(m);
var parentRadio = m._cfg.get("parentRadio", nil);
if (parentRadio != nil) {
m.radioGroup = parentRadio.radioGroup;
} else {
m.radioGroup = gui.widgets.RadioButtonsGroup.new();
}
m.radioGroup.addRadio(m);
return m;
},
del: func()
{
var pr = getParent();
if (contains(pr, "radioGroup") {
pr.radioGroup.removeRadio(me);
}
setText: func(text) {
me._view.setText(me, text);
return me;
},
setCheckable: nil,
setChecked: func(checked = 1)
{
# call our base version
me.parents[0].setChecked(checked);
if (checked) {
me._setRadioGroupSiblingsUnchecked();
setChecked: func(checked = 1) {
if (me._checked == checked) {
return me;
}
me._setRadioGroupSiblingsUnchecked();
me._trigger("toggled", {checked: checked});
me._checked = checked;
me._onStateChange();
return me;
},
_setRadioGroupSiblingsUnchecked: func {
me.radioGroup._updateChecked(me);
},
toggle: func {
me.setChecked(!me._checked);
return me;
},
_setView: func(view) {
call(gui.Widget._setView, [view], me);
var el = view._root;
el.addEventListener("click", func {
if (me._enabled) {
me.setChecked()
}
});
el.addEventListener("drag", func(e) e.stopPropagation());
},
# protected members
_setRadioGroupSiblingsUnchecked: func
{
var pr = getParent();
if (contains(pr, "radioGroup") {
pr.radioGroup._updateChecked(me);
} else {
# todo, remove me, it's okay to manually manage RadioButtons
logprint(LOG_DEV, "No radio group defined");
}
}
};
# auto manage radio-button checked state
gui.widgets.RadioGroup = {
new: func(nm = 'unnamed')
gui.widgets.RadioButtonsGroup = {
new: func(name = "unnamed")
{
var m = {parents:[gui.widgets.RadioGroup, name:nm, radios:[]]};
var m = {
parents: [gui.widgets.RadioButtonsGroup],
name: name,
radios: [],
};
return m;
},
addRadio: func(r)
{
if (r.parents[0] != RadioButton) {
logprint(LOG_ALERT, "Adding non-RadioButton to RadioGroup")
return;
}
r.listen("toggled", func(e) {
me._updateChecked(r);
});
append(me.radios, r);
},
removeRadio: func(r)
{
if (r.parents[0] != RadioButton) {
logprint(LOG_ALERT, "Remove non-RadioButton from RadioGroup")
return;
# XXX should we update some other item to be checked ?
if (contains(me.radios, r)) {
var index = find(r, me.radios);
me.radios = subvec(me.radios, 0, index) ~ subvec(me.radios, index + 1);
}
# should we update some other item to be checked?
me.radios.remove(r);
},
setEnabled: func(doEnable = 1)
setEnabled: func(enabled = 1)
{
foreach (var r : me.radios) {
r.setEnabled(doEnable);
foreach (var r; me.radios) {
r.setEnabled(enabled);
}
},
# protected methods
# update check state of all radios in the group
_updateChecked: func(active)
{
foreach (var r : me.radios) {
r.setChecked(r == active);
foreach (var r; me.radios) {
if (r != active) {
r.setChecked(0);
}
}
}
};
},
};

View file

@ -209,5 +209,53 @@
<green type="float">0.15</green>
<blue type="float">1</blue>
</list_item_bg_selected>
<radio_button_bg_color>
<red type="float">0.949</red>
<green type="float">0.945</green>
<blue type="float">0.941</blue>
</radio_button_bg_color>
<radio_button_bg_color_hovered>
<red type="float">0.989</red>
<green type="float">0.985</green>
<blue type="float">0.981</blue>
</radio_button_bg_color_hovered>
<radio_button_selected_indicator_bg_color>
<red type="float">1</red>
<green type="float">1</green>
<blue type="float">1</blue>
</radio_button_selected_indicator_bg_color>
<radio_button_selected_indicator_bg_color_hovered>
<red type="float">0.95</red>
<green type="float">0.95</green>
<blue type="float">0.95</blue>
</radio_button_selected_indicator_bg_color_hovered>
<radio_button_selected_indicator_bg_color_disabled>
<red type="float">0.9</red>
<green type="float">0.9</green>
<blue type="float">0.9</blue>
</radio_button_selected_indicator_bg_color_disabled>
<radio_button_selected_indicator_border_color>
<red type="float">0.5</red>
<green type="float">0.5</green>
<blue type="float">0.5</blue>
</radio_button_selected_indicator_border_color>
<radio_button_selected_indicator_color>
<red type="float">0.25</red>
<green type="float">0.25</green>
<blue type="float">1</blue>
</radio_button_selected_indicator_color>
<radio_button_selected_indicator_color_disabled>
<red type="float">0.5</red>
<green type="float">0.5</green>
<blue type="float">1</blue>
</radio_button_selected_indicator_color_disabled>
</colors>
</PropertyList>