QML application launcher similar to iOS - qml

I'm trying to write an application launcher using QtQuick\QML, and I'd like the user experience to be similar to iOS, in terms of having a grid of icons that can be rearranged with icons that "move out of the way" via animated transitions and a "snap to grid" effect if the icon is dropped in an intermediate position. I've tried using GridView and the drag properties, but I can't seem to get the layout do what I want. What would be the best way to implement this type of app using QML? I'm fairly new to QtQuick, and I feel like maybe I'm missing something fundamental that would make this fairly easy\obvious to write.

For putting icons in a grid, you can use the grid view:
http://developer.qt.nokia.com/doc/qt-4.8/qml-gridview.html
Go through the Qt Quick documentation, you will find out how to do this.

This is not directly relevant to implementing the grid of icons, but I recently came across the QML component Loader. This lets you load QML components on demand, and could be useful for the code that launches an app after the icon is selected.
http://doc-snapshot.qt-project.org/5.0/qml-qtquick2-loader.html

I have made Nokia N9 launched look and feel (Maemo 6, or also known as MeeGo).
It is similar, I just scroll from up to down with icons, while you change "pages" from left to right (and vice versa).
I don't know is it best way, but this is how I did icon manager (its shrinked, this is only to give you idea - in reality it is considerably larger):
Item
{
id: root
function getChildAt(x, y) {}
function getIndexOfChild(child) {}
function moveChild(child, x, y)
{
//moving around icons
}
function setIndexToChild(child)
{
//index of child in Grid element (where to drop)
}
Flickable
{
id: scroller
clip: true
//you most likely want HorizontalFlick ("paging" effect you can add on onBeginingXChanged)
flickableDirection: Flickable.VerticalFlick
contentHeight: iconTable.height
contentWidth: iconTable.width
Grid
{
id: iconTable
width: root.width
anchors.top: parent.top
flow: Grid.LeftToRight
spacing: 10
add: Transition
{
NumberAnimation
{
properties: "x,y"
//make desired transition
}
}
move: Transition
{
NumberAnimation
{
properties: "x,y"
//make desired transition
}
}
}
}
}
You could also write down your own implementation of manager in C++ and later on use it in QML.
This is how it looks like:

I created something distantly connected to this recently, the idea is: create a ListView with snapping. Its delegate should contain a GridView. Separate all of the apps into n-element chunks. Then (it's only the idea)
ListModel
{
ListElement { apps: [app1, app2, ..., appn] }
ListElement { apps: [app1, app2, ..., appn] }
....
ListElement { apps: [app1, app2, ..., appk] }
}
Then populate the ListView with this model and the GridView with the apps property.
I don't know whether you can provide drag and drop here, though

Related

How can one write a WatchOS widget for accessoryCorner family that renders appropriately?

I'm trying to build a widget that has a gauge like in the image attached. It does not seem like there are any APIs to render the gauge (or any other view for that matter) on an arc, depending on which corner is used.
Is there any such support, or are such widgets only available to Apple? E.g. can one tell which corner the widget is being rendered in, so that the correct transformations be computed?
Thank you!
You can get close to an Apple style corner widget, but there are currently some limitations. As far as I know you have to use the .widgetLabel modifier which restricts you to an "Image, Text, Gauge, ProgressView, or a container with multiple subviews".
The styling for the Gauge and ProgressView seem to be predefined as well - for example styling the gauge with .gaugeStyle(LinearCapacityGaugeStyle()) doesn't change the appearance.
var body: some View {
switch widgetFamily {
case .accessoryCorner: // WatchOS only
Text("50%") // Watch out for clipping
.font(.system(size: 20))
.foregroundColor(.blue)
.widgetLabel {
ProgressView(value: 0.5)
.tint(.blue)
}
}
}
or
var body: some View {
switch widgetFamily {
case .accessoryCorner: // WatchOS only
Text("50%") // Watch out for clipping
.font(.system(size: 20))
.foregroundColor(.blue)
.widgetLabel {
Gauge(value: 50.0, in: 0...100) {
Text("Not shown")
} currentValueLabel: {
Text("Not shown")
} minimumValueLabel: {
Text("0") // Watch out for clipping
} maximumValueLabel: {
Text("100") // Watch out for clipping
}
.tint(.blue)
.gaugeStyle(LinearCapacityGaugeStyle()) // Doesn't do anything
}
Gives you:
You can rotate the text manually to try and make it line up with corner, but as you say then there doesn't seem to be a way to identify which corner the widget is in so you don't know which way to rotate it...

Binding a view to a changing controller property

I'm working in Kotlin with the TornadoFX library. Imagine you have a toolbar which shows the tool that are useful for the current view you have. So we have a MainController which has a subController property which is the controller of some view next to the tool bar. So if our subController changes, the view should update. Also, if any property (e.g. selectedTool, tools) of the subController changes, the toolbar should update accordingly. Momentarily, the toolbar is not updated.
class ToolBar : View("Tool bar") {
private val controller: MainController by inject()
override val root = vbox {
tilepane {
for (tool in controller.subController.tools) {
button(tool.name, group).action {
controller.subController.changeTool(tool) // changes selected tool
}
}
}
this += controller.subController.selectedTool.options
}
}
Extra info: subController.tools is an ArrayList and subController.selectedTool is a Tool.
Now my question is, what's the recommended way to do this in TornadoFX?
You have several options. A Parent supports a function called bindChildren which accepts an observable list of items and a function to turn each of these items into a Node. You can use this to create your buttons in the toolbar:
tilepane {
bindChildren(controller.subController.tools) { tool ->
Button(tool.name) ...
}
}
You can also do this manually if you need more control:
tilepane {
controller.subController.tools.onChange {
children.clear()
// create new buttons here, like in your example
}
}
However, instead of injecting controller to access subController to get to the tools, you should have a ToolsModel which is injected into the current scope. The tools model could have a list of tools and the selected tools and can be injected into all views and controllers which needs it. You say that selectedTool is a Tool, but you're not showing what a Tool is, but judging from your code it looks like Tool.options is a Node subclass (?).
You can add/remove the tool.options element using the same technique, or even wrap it in a stackpane or other layoutcontainer to be able to identify the tool to remove (or simply remove all children of the stackpane) on change using the same technique.

Dynamically set Label's "id" property

I'm developing an application for SailfishOS using the QML language.
I want to dynamically set the id property of a Label by using an if condition.
This is my code:
Label {
id: {
if(myBool == false) {
thisText()
} else {
notThatText()
}
}
width: parent.width
horizontalAlignment: Text.AlignRight
text: ""
font.pixelSize: Theme.fontSizeLarge
}
This code is placed into my CoverPage.qml file, the one that display things on the application's cover while in background.
By doing this, the cover is simply black, nothing is displayed.
Is it possible in QML to do this?
Thanks in advance!
The Qt doc says this.
While it may look like an ordinary property, the id attribute is not an ordinary property attribute, and special semantics apply to it;
You cannot set the id of a QML component at runtime.(Correct me if I am wrong). You might find objectName property useful. But I don't understand why you are trying to assign dynamic id.
I have a use case where use a dynamic/specific id could be useful. The id could be view with Gammaray, it can help for debugging.
GridLayout {
id: layout
Repeater {
model: foo
Bar {
id: bar_X_Y // bar_{model.row}_{model.column}
}
}
}
But as far as I know, it's not possible.

Sencha Touch 2 Component in list emptyText

I have a list component that I want to display a button to send a suggestion for the data to be included if it turns up no results.
List component itself is implemented like this:
{
xtype: 'list',
itemTpl: '{name}',
// This is not ideal!
emptyText: [
'<div class="x-button-normal x-button">',
'<span class="x-button-label">',
'Suggest <i><span id="suggest-name"></i>',
'</span>',
'</div>'
].join(''),
store: 'TheStore'
}
And this is the handler for the search field that simply sets a substring filter on the store:
'keyup': function(self, e, eOpts) {
queryString = self.getValue();
 
var store = Ext.getStore('TheStore');
store.clearFilter();
 
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
// Changes the button so it shows name
document.getElementById('suggest-name').innerText = queryString;
}
},
Right now, I have the emptyText set to some simple HTML that emulates the look of a Sencha Touch button, but this means I have none of the button behaviour since it's not tied into the component system (such as being depressed when tapped). How can I set the emptyText attribute (or emulate it) since a proper button is displayed instead?
Try to view the two screencasts below
Sencha Touch - Intro to Nested List Component
Sencha Touch 2 -
Intro to List Component
I know it's about 2 years too late... but I ran into the same problem as #Hampus Nilsson and when I found the solution, I figured if I was running into this 2 years later, others might run into it as well.
With that said... I'm currently running Sencha Touch version 2.3.1. The solution, as it pertains to that version, was really easy to implement, just super tricky to find. The problem is that Sencha has a CSS property on the emptyText component (x-list-emptytext class) that is ignoring all pointer interactions called pointer-events: none; (who knew?!)
This property is found in:
[sdk_root]/resources/themes/stylesheets/sencha-touch/base/src/dataview/_List.scss
.x-list-emptytext {
text-align: center;
pointer-events: none; // THIS ONE!!
font-color: #333333;
#include st-box();
#include st-box-orient(vertical);
#include st-box-pack(center);
}
To fix this, simply override that property in your own sass/css. I chose to override it with pointer-events: inherit; but your mileage may vary.
THEN, all you need to do is setup a listener on your list, I recommend in the initialize function of your list class, like the so:
this.emptyTextCmp.element.on({
delegate: '.x-button-normal',
scope: this,
tap: this.yourCustomFunction
});
Where this is your list component. It's important to note that you need a "." in front of the class name of your delegate. In the above example, I set the delegate to: '.x-button-normal', because that was one of the two classes listed in the question's code. I could've also used '.x-button'. If it were me, I'd give your html an additional class, to be used as the delegate, that helps identify it a little better, instead of just using the default Sencha class as your delegate. That's an opinion, not a requirement.
That's it, I hope this helps someone else!

Displaying Custom Images in 'tools' config options of ext.grid.panel

I am only a month old with extjs and still experimenting. My question is: I have a grid panel and within it the 'tools' config options. I am using this to enable/disable a Ext.grid.feature.Grouping variable. The 2 handler functions have the logic to disable/enable the 2 views by clicking on the 2 'cross' buttons that appear on the right side of the header. The logic is fine. However, I would like to display my set of custom images in place of the 'cross' buttons. Can this be done? If yes, how? Do I need to make some changes in the css code for that?
I have looked into the documentation and also done a good search but nothing seems to answer my question.
Specify a custom type config on your tools:
Ext.create('Ext.grid.Panel', {
...
tools: [
{
type: 'enable-grouping',
handler: function() {
...
}
},
{
type: 'disable-grouping',
handler: function() {
...
}
}
]
});
Then define the following classes in a stylesheet to style your new tools:
.x-tool-enable-grouping {
background-image: url('path/to/tool/image/enable-grouping.png');
}
.x-tool-disable-grouping {
background-image: url('path/to/tool/image/disable-grouping.png');
}
The size of a tool image should be 15 x 15 px