I'm trying to implement a BB10 settings menu, looking like the one in the Calendar app for example. The question here is, which components should I use? Using a ListView with an XML model looks great, but is incompatible with translation. Using a C++ model looks overkill for a simple menu with a couple of entries…
There's probably an established pattern somewhere, but I can't find it.
Screenshot of the Calendar app settings view
What you want is the expendable content property of the title bar:
I would create a QML object that you can re-use for each entry with properties for title and image.
So for example, something perhaps like this:
SettingEntry.qml
Container {
property alias title:title.Text
signal click()
TextView {
id: title
text: "[title goes here]"
}
gestureHandlers: [
TapHandler {
onTapped: {
click();
}
}
]
}
Then in your settings page you would use it like a normal object:
Page {
Container {
SettingEntry {
title: "General"
onClick: {
//open general page
}
}
SettingEntry {
title: "Invitation Settings"
}
}
}
The above is obviously very simplified, you would want to include an icon image, add translation code and add visual adjustments like filling the width and padding.
It should however give you a good idea of where to start.
I also included a gesturehandler and signal to show you how to handle events such as a click.
Related
I'd like to append a new menu entry right below "Enter Full Screen", but I am failing to find the right CommandGroupPlacement property.
CommandGroup(after: .<what needs to be put here??>) {
//my buttons here
}
Attempting to override "View" results in just another group with the same name (see image).
CommandMenu("View") {
//add button here
}
Shoutout to Majid Jabrayilov for his blogpost on this: https://swiftwithmajid.com/2020/11/24/commands-in-swiftui/
To find a solution to my above issue though I still had to think a bit around the corner–what does work is this:
CommandGroup(before: .toolbar) {
Button("Foo") {
}
}
This works, because the toolbar menu entry is located within "View" (even thought I don't have a toolbar in my app, the placement still works nonetheless...)
You said you were looking for the proper CommandGroupPlacement so for your case (relative to full screen mode), you would technically want CommandGroupPlacement.sidebar. CommandGroupPlacement.toolbar works because toolbar options live in the View menu, though you have none set.
/// Example in a CommandsBuilder
CommandGroup(after: CommandGroupPlacement.sidebar) {
Button("New View Action", action: { print("After sidebar menu options") }).keyboardShortcut("s", modifiers: [.command, .option, .control, .function]
}
This should also come in handy for others. The Apple documentation that corresponds to this: CommandGroupPlacement
I'm new to Webix and trying to create a list or dataview where users can add and remove itens. (font files this time)
For such i defined one "add" button and one list where previously added items are displayed.
My plan was to put an label and a exclude button into each item of the list with the components Webix already provides but to my surprize the template property of data components aparentily can't be definied with ui objects itself.
There is some way to do it?
Somethink like it:
webix.ui({ id:'stage', rows:[
{ view:"button", type:"icon", icon:"plus", label:"Add Font", autowidth:true, click:AddFont },
{ view:"dataview", id:"fnt_list", data:fonts(), width:300,
type:{ width:300, height:150, template:function(fnt)
{
return webix.ui({cols:[
{view:"label", align:"left", label:fnt.fileName },
{view:"button", type:"icon", icon:"trash", label:"Exclude", align:"right", autowidth:true }
]});
}}
}]});
I know it can be made with the layout component alone but i really would like to do it with one of the data components because of the paging feature they have.
While it possible to create a separate instance of webix UI for each row, it is overkill for your task, just use HTML markup in the template. Something like next
{ view:"dataview", css:"fonts", id:"fnt_list", data:fonts, width:300,
type:{
width:300, height:150,
template:"#fileName# <i class='fa fa-trash-o'></i>"
},
working snippet - https://snippet.webix.com/dvbdt6st
If you still want to have real UI widgets inside of dataview items, check
https://docs.webix.com/desktop__data_layout.html
and
https://docs.webix.com/desktop__active_content.html
I want to automatically make links (e.g. https://xmpp.org/) into the text of a Text element clickable, so the link can be opened in a browser (without manually copying the link).
I can't add e.g. manually in my code, because the input comes directly from users.
Has Qt a simple solution for this in QtQuick/QML?
You can use something like that(Regex is from this answer);
Text {
property string text2: "http://www.google.com"
text: isValidURL(text2) ? ("<a href='"+text2+"'>"+text2+"</a>") : text2
onLinkActivated:{
if (isValidURL(text2)){
Qt.openUrlExternally(text2)
}
}
function isValidURL(str) {
var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*#)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%#!\-\/]))?/
return regexp.test(str);
}
}
You can use TextArea or TextEdit components, set textFormat property to TextEdit.RichText and listen to onLinkActivated signal.
E.g.
TextArea {
id: ...
textFormat: TextEdit.RichText
onLinkActivated: Qt.openUrlExternally( link )
}
Note: in order the link in browser you need to use Qt.openUrlExternally
One hint, in order to make the component not editable (so that user can not type in), DO NOT set enabled property (inherited from Item) to false, use readOnly property instead. Setting enabled would make link unclickable.
I have created a custom ribbon button following the steps mentioned in http://jondjones.com/how-to-add-a-custom-sitecore-button-to-the-editor-ribbon/
I can see the button appearing in sitecore:
Custom button
Command does not get triggered when clicked on the button.
Below is my code:
using System;
using Sitecore.Shell.Applications.Dialogs.ProgressBoxes;
using Sitecore.Shell.Framework.Commands;
namespace SitecoreVsPoc.Commands
{
public class TranslateContent : Command
{
private static readonly object Monitor = new object();
public override void Execute(CommandContext context)
{
if (context == null)
return;
try
{
ProgressBox.Execute("Arjun", "Title", "Applications/32x32/refresh.png", Refresh);
}
catch (Exception ex)
{
Sitecore.Diagnostics.Log.Error("Error!", ex, this);
}
}
public void Refresh(params object[] parameters)
{
// Do Stuff
}
}
}
Below is the command I have registered in commands.config:
<command name="contenteditor:translatecontent" type="SitecoreVsPoc.Commands.TranslateContent,SitecoreVsPoc" />
Note: I am using Sitecore 8.2 initial release.
Can someone suggest a solution for this?
In Sitecore 8 it was changed the way you add Ribbon button. As far I see your link is from Sitecore 7 or 6.
To create the new button item for the Experience Editor ribbon:
In the Core database, open the Content Editor and navigate to /sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor/Edit.
Create a new item based on the relevant ribbon control template, for example, the Small Button template. The templates are located at /sitecore/templates/System/Ribbon/.
For the new item, add the following information:
In the Header field, enter the display name of the button.
In the ID field, enter a unique identifier for the item. For example, you can include the ribbon group name in the ID.
In the Icon field, enter the path to the relevant icon. Depending on the button you create, adjust the icon size accordingly.
Open Sitecore Rocks and add the relevant control rendering, for example SmallButton, to the layout of the button item you created.
Enter a unique ID for the rendering.
For other SPEAK controls, you can point to another item in the Data Source field and specify the configuration in this other item.
Important
More informations you can find here: https://doc.sitecore.net/sitecore_experience_platform/content_authoring/the_editing_tools/the_experience_editor/customize_the_experience_editor_ribbon
http://reyrahadian.com/2015/04/15/sitecore-8-adding-edit-meta-data-button-in-experience-editor/
Before it was very simple, you didn't need to add new code:
https://blog.istern.dk/2012/05/21/running-sitecore-field-editor-from-a-command/
I have a global singleton "Settings" which holds application settings. When I try to run the following code I get a QML CheckBox: Binding loop detected for property "checked":
CheckBox {
checked: Settings.someSetting
onCheckedChanged: {
Settings.someSetting = checked;
}
}
It is obvious why this error occurs, but how can I correctly implement this functionality without a binding loop? E.g. I want to save the current checked state of the checkbox in the settings singleton.
I am using Qt 5.4 and Qml Quick 2.
Regards,
Don't bind it. Because the check box does not fully depend on Setting.someSetting.
When a user clicked the checkbox, the CheckBox.checked is changed by itself. At the same time, the property binding is no longer valid. Settings.someSetting cannot modify the CheckBox after it is clicked by user. Therefore, the checked: Settings.someSetting binding is wrong.
If you want to assign an initial value to the check box when the component is ready, use Component.onCompleted to assign it:
CheckBox {
id: someSettingCheckBox
Component.onCompleted: checked = Settings.someSetting
onCheckedChanged: Settings.someSetting = checked;
}
If you are working on a more complex scenario, the Setting.someSetting may be changed by some other things during runtime and the state of the check box is required to be changed simultaneously. Catch onSomeSettingChanged signal and explicitly changed the check box. Submit the value of someSettingCheckBox to Settings only when the program/widget/dialog/xxx finished.
CheckBox { id: someSettingCheckBox }
//within the Settings, or Connection, or somewhere that can get the signal.
onSomeSettingChanged: someSettingCheckBox.checked = someSetting
I prefer this solution
// Within the model
Q_PROPERTY(bool someSetting READ getSomeSetting WRITE setSomeSetting NOTIFY someSettingChanged)
void SettingsModel::setSomeSetting(bool checkValue) {
if (m_checkValue != checkValue) {
m_checkValue = checkValue;
emit someSettingChanged();
}
}
// QML
CheckBox {
checked: Settings.someSetting
onCheckedChanged: Settings.someSetting = checked
}
The trick is you protect the emit with an if check in the model. This means you still get a binding loop but only a single one, not an infinite one. It stops when that if check returns false thereby not emitting to continue the loop. This solution is very clean, you do not get the warning, and yet you still get all the benefits of the binding.
I want to talk about the limitations of the other solutions presented
CheckBox {
Component.onCompleted: checked = Settings.someSetting
onCheckedChanged: Settings.someSetting = checked;
}
In this solution you lose your binding. It can only have a default setting on creation and be changed by the user. If you expand your program such that other things change the values in your model, this particular view will not have a way to reflect those changes.
Settings {
id: mySettings
onSomeSettingChanged: checkBox.checked = someSetting
}
CheckBox {
id: checkBox
onCheckedChanged: mySettings.someSetting = checked
}
This solution was mentioned to address these problems but never written out. It is functionally complete. Model changes are reflected, the user can change the data, and there are no binding loops because there are no bindings; only two discrete assignments. (x: y is a binding, x = y is an assignment)
There are a couple problems with this. The first is that I think its ugly and inelegant, but that is arguably subjective. It seems fine here but if you have a model representing 10 things in this view, this turns into signal spaghetti. The bigger problem is that it does not work well with delegates because they only exist on demand.
Example:
MyModel {
id: myModel
// How are you going to set the check box of a specific delegate when
// the model is changed from here?
}
ListView {
id: listView
model: myModel.namesAndChecks
delegate: CheckDelegate {
id: checkDelegate
text: modelData.name
onCheckStateChanged: modelData.checkStatus = checked
}
}
You can actually do it. I've made up custom QML signals and connections to do it, but the code complexity makes me want to hurl, and even worse you could possibly be forcing creation of a delegate when it is not necessary.
If you don't want to make a binding loop - don't make a binding, use a proxy variable, for example. Other simple solution can be to check the value:
CheckBox {
checked: Settings.someSetting
onCheckedChanged: {
if (checked !== Settings.someSetting) {
Settings.someSetting = checked;
}
}
}
You can also make two-way binding to resolve this issue:
CheckBox {
id: checkBox
Binding { target: checkBox; property: "checked"; value: Settings.someSetting }
Binding { target: Settings; property: "someSetting"; value: checkBox.checked }
}
Sometimes it is useful to separate input and output values in control. In this case control always displays real value and it can also show a delay to the user.
CheckBox {
checked: Settings.someSetting
onClicked: Settings.someSetting = !checked
}