Thursday, March 8, 2012

A Disabled Tab and Adding Tabs on the Fly

A custom tab control received a slight update: An isDisabled property was added to the CustomTab. The disabled tab does absolutely nothing - does not respond to mouse clicks or mouse enter and exit events. Its name is displayed in gray. So a couple changes were done to the CustomTab which are summarized below.

import QtQuick 1.0

Rectangle {
...
property bool isDisabled;
property int tabIndex;

function applyState()
{
...
if(isDisabled)
{
textOnTab.color = "darkgrey";
}
}

MouseArea{
hoverEnabled: true
anchors.fill: parent
onClicked: {
if(!isDisabled)
{
...
}
}
...
}

The JavaScript for the main control was modified to become somewhat more generic. There is certainly space for some more improvement! Tabs are currently added with the minimum number of properties. When all the tabs are added, the recalculateTabProperties() is called to calculate properties of each tab such as width, margins or anchors using the total number of tabs and the index of the current tab as starting points. The applyXMLModel() is totally optional, it just sits there so that the code that reads the XML is not lost.

Another bit of functionality is adding a tab "on the fly", to the right of the existing tabs. Using the changes above, the addOneMoreTab() function adds a CustomTab object to the children of the tabsRow element. Currently this function modifies the iPosition of the previous tab to make sure it's no longer marked as rightmost. As an improvement, this bit can be moved into the recalculateTabProperties(), where it most likely belongs. The way the tab is added is shown on the screenshots.

Tab Control Loaded

New Tab Added Dynamically

Full code of the main application.

import QtQuick 1.0

Rectangle {
id: screen
width: 490; height: 400
property int numTabs: 5
property int margin: 2
property string transparentColor : "transparent"
property string redColor: "red"
property string grayColor: "#B7B9BC" // "lightgray"

function addOneMoreTab()
{
//get the current tab count
var numTabs = tabsRow.children.length;
//get the last tab and change its position state
var lastTab = tabsRow.children[numTabs-1];
lastTab.iPosition = 1;
//add the new tab
var tab = Qt.createComponent("CustomTab.qml");
var obj = tab.createObject(tabsRow);

obj.tabIndex = tabsRow.children.length;
obj.tabtext = "Just Added";

recalculateTabProperties();

tabsRow.clearState();
}

function recalculateTabProperties()
{
var numTabs = tabsRow.children.length;
var i=0;
for(i=0;i<=numTabs-1;i++)
{
console.log("recalculating tab " + i);

var obj = tabsRow.children[i];
if(i==0)
{
obj.iPosition = 0;
}
else if(i==numTabs-1)
{
obj.iPosition = 2;
}
else
{
obj.iPosition = 1;
}

obj.ctlHeight = tabsRow.height - margin;
obj.isSelected = false;
obj.anchors.bottom = tabsRow.bottom;
obj.anchors.bottomMargin = margin;

if(obj.iPosition == 0)
{
obj.ctlWidth = tabsRow.width/numTabs;
obj.anchors.left = tabsRow.left;
}
else
{
obj.ctlWidth = tabsRow.width/tabsRow.children.length - margin;
obj.anchors.left = tabsRow.children[i-1].right;
obj.anchors.leftMargin = margin;
}
}
}

function createTab()
{
var tab = Qt.createComponent("CustomTab.qml");

if(tab.status == Component.Ready)
{
var obj = tab.createObject(tabsRow);
if(obj == null)addOneMoreTab();
{
return false;
}

var numTabs = tabsRow.children.length
console.log("tabsRow children:" + numTabs)

obj.tabIndex = numTabs;
}
return true;
}

function applyXMLModel()
{
var i=0;
for(i=0;i<=xmlTabModel.count-1;i++)
{
var obj = tabsRow.children[i];
if(obj != null)
{
console.log("obj is not null")
if(xmlTabModel.get(i).size == "Disabled")
{
obj.tabtext = "Disabled";
obj.isDisabled = true;
}
else
{
obj.tabtext = xmlTabModel.get(i).name;
}
}
}
}

function createTabs(num)
{
var i=0;

for(i=0;i<=num-1;i++)
{
var success = createTab();
if(!success)
{
console.log("Failed to create tab #" + i);
}
}

recalculateTabProperties();
applyXMLModel();

tabsRow.clearState();
}

XmlListModel{
id: xmlTabModel
source: "tabs.xml"
query: "/tabList/tab"
XmlRole{name: "name"; query: "name/string()" }
XmlRole{name: "size"; query: "size/string()"}

onCountChanged: {
createTabs(count);
}
}

Rectangle {
id: backRect
radius: 10
width: parent.width
height: parent.height - 50 // need to expand to free space
color: grayColor
anchors.top: parent.top
anchors { leftMargin: 10; bottomMargin: 10; topMargin: 10; rightMargin:10 }

Rectangle{
id: tabsRect
radius: 10
width: parent.width
height: 80
anchors.top: parent.top

Row{
id:tabsRow
width: parent.width
height: parent.height

function clearState()
{
var j=0;
for(j=0;j<= tabsRow.children.length - 1;j++)
{
children[j].isSelected = false;
children[j].state = "unselected";
children[j].applyState();
}
}
}
}
}

Rectangle{
id: buttonRect
height: 40
width: 75
border.width: 1
border.color: "black"
anchors.bottom: parent.bottom

Text{
text: "Click Here"
x:5
y:10
}

MouseArea{
anchors.fill: parent
onClicked: {
addOneMoreTab();
}
}
}
}
by . Also posted on my website

No comments: