Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Q
qtquickcontrols-nemo
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
NemoMobile
qtquickcontrols-nemo
Commits
4f8d9d1f
Commit
4f8d9d1f
authored
Jun 01, 2017
by
eekkelund
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Keyboard] Move application upwards in case of input area is clicked and keyboard appeares
parent
2862bfd7
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
345 additions
and
262 deletions
+345
-262
ApplicationWindow.qml
src/controls/ApplicationWindow.qml
+345
-262
No files found.
src/controls/ApplicationWindow.qml
View file @
4f8d9d1f
/*
/*
* Copyright (C) 2013 Andrea Bernabei <and.bernabei@gmail.com>
* Copyright (C) 2013 Andrea Bernabei <and.bernabei@gmail.com>
* Copyright (C) 2013 Jolla Ltd.
* Copyright (C) 2017 Eetu Kahelin
*
*
* This library is free software; you can redistribute it and/or
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* modify it under the terms of the GNU Library General Public
...
@@ -28,15 +30,14 @@ import QtQuick.Controls.Styles.Nemo 1.0
...
@@ -28,15 +30,14 @@ import QtQuick.Controls.Styles.Nemo 1.0
NemoWindow
{
NemoWindow
{
id
:
root
id
:
root
width
:
320
height
:
640
property
alias
header
:
toolBar
property
alias
header
:
toolBar
/*! \internal */
/*! \internal */
default
property
alias
data
:
contentArea
.
data
default
property
alias
data
:
contentArea
.
data
property
alias
pageStack
:
stackView
property
alias
pageStack
:
stackView
property
alias
initialPage
:
stackView
.
initialItem
property
alias
initialPage
:
stackView
.
initialItem
property
bool
applicationActive
:
Qt
.
application
.
active
property
alias
orientation
:
contentArea
.
uiOrientation
property
alias
orientation
:
contentArea
.
uiOrientation
readonly
property
int
isUiPortrait
:
orientation
==
Qt
.
PortraitOrientation
||
orientation
==
Qt
.
InvertedPortraitOrientation
readonly
property
int
isUiPortrait
:
orientation
==
Qt
.
PortraitOrientation
||
orientation
==
Qt
.
InvertedPortraitOrientation
...
@@ -140,294 +141,376 @@ NemoWindow {
...
@@ -140,294 +141,376 @@ NemoWindow {
Item
{
Item
{
id
:
backgroundItem
id
:
backgroundItem
anchors.fill
:
parent
anchors.centerIn
:
parent
// NOTE: Using Screen.height/width will cause issues when the app is not fullscreen (e.g. when testing using Qt desktop)
// because in that case the app window will be smaller but the content will still be for fullscreen size
width
:
__transpose
?
Screen
.
height
:
Screen
.
width
height
:
__transpose
?
Screen
.
width
:
Screen
.
height
rotation
:
rotationToTransposeToPortrait
()
rotation
:
rotationToTransposeToPortrait
()
//This is the rotating item
Item
{
Item
{
id
:
contentArea
id
:
clipping
width
:
parent
.
width
height
:
parent
.
height
anchors.centerIn
:
parent
property
int
_horizontalDimension
:
parent
?
parent
.
width
:
0
property
int
_verticalDimension
:
parent
?
parent
.
height
:
0
property
alias
defaultOrientationTransition
:
orientationState
.
defaultTransition
// This is used for states switching
property
int
filteredOrientation
//this is the reliable value which changes during the orientation transition
property
int
uiOrientation
property
bool
orientationTransitionRunning
:
false
StackView
{
id
:
stackView
anchors.top
:
root
.
isUiPortrait
?
toolBar
.
bottom
:
parent
.
top
anchors.right
:
parent
.
right
anchors.left
:
root
.
isUiPortrait
?
parent
.
left
:
toolBar
.
right
anchors.bottom
:
parent
.
bottom
clip
:
true
Component.onCompleted
:
stackInitialized
=
true
//IMPORTANT: this property makes it so that at app startup we wait for the initial page to be pushed
//before determining the initial ui orientation (see the states logic below)
//If we don't use this, the orientation will change first time based on NemoWindow's allowedOrientation,
//and the second time based on the allowedOrientations of the initialItem of the stack.
//Using this property avoids that, and make the UI directly start in the correct orientation
//TODO: find a cleaner way to do it (if there's any)
property
bool
stackInitialized
:
false
onStackInitializedChanged
:
if
(
stackInitialized
)
{
//set Screen.orientation as default, if allowed
if
(
root
.
isOrientationAllowed
(
Screen
.
orientation
))
{
contentArea
.
filteredOrientation
=
Screen
.
orientation
}
else
{
//let the window handle it, it will fall back to an allowed orientation
root
.
fallbackToAnAllowedOrientation
()
}
}
//this has to be a function, property won't work inside onCurrentItemChanged, as the property binding hasn't been updated yet there
//(hence we'd be using the old currentItem)
function
_isCurrentItemNemoPage
()
{
return
currentItem
&&
currentItem
.
hasOwnProperty
(
"
__isNemoPage
"
)
}
//update orientation constraints when a Page is pushed/popped
onCurrentItemChanged
:
{
if
(
_isCurrentItemNemoPage
())
root
.
orientationConstraintsChanged
()
}
//This properties are accessible for free by the Page via Stack.view.<property>
z
:
1
readonly
property
int
orientation
:
contentArea
.
uiOrientation
width
:
parent
.
width
-
(
isUiLandscape
?
stackView
.
panelSize
:
0
)
property
alias
allowedOrientations
:
root
.
allowedOrientations
height
:
parent
.
height
-
(
isUiPortrait
?
stackView
.
panelSize
:
0
)
property
alias
orientationTransitionRunning
:
contentArea
.
orientationTransitionRunning
clip
:
stackView
.
panelSize
>
0
Connections
{
//This is the rotating item
id
:
pageConn
Item
{
target
:
stackView
.
_isCurrentItemNemoPage
()
?
stackView
.
currentItem
:
null
id
:
contentArea
onAllowedOrientationsChanged
:
root
.
orientationConstraintsChanged
()
anchors.centerIn
:
parent
transform
:
Scale
{
id
:
contentScale
property
bool
animationRunning
:
xAnim
.
running
||
yAnim
.
running
Behavior
on
xScale
{
NumberAnimation
{
id
:
xAnim
;
duration
:
100
}
}
Behavior
on
yScale
{
NumberAnimation
{
id
:
yAnim
;
duration
:
100
}
}
}
}
delegate
:
StackViewDelegate
{
property
int
_horizontalDimension
:
parent
?
parent
.
width
:
0
pushTransition
:
Component
{
property
int
_verticalDimension
:
parent
?
parent
.
height
:
0
StackViewTransition
{
PropertyAnimation
{
property
alias
defaultOrientationTransition
:
orientationState
.
defaultTransition
target
:
enterItem
property
:
"
x
"
// This is used for states switching
from
:
target
.
width
property
int
filteredOrientation
to
:
0
duration
:
500
//this is the reliable value which changes during the orientation transition
easing.type
:
Easing
.
OutQuad
property
int
uiOrientation
}
PropertyAnimation
{
property
bool
orientationTransitionRunning
:
false
target
:
exitItem
property
:
"
x
"
StackView
{
from
:
0
id
:
stackView
to
:
-
target
.
width
anchors.top
:
root
.
isUiPortrait
?
toolBar
.
bottom
:
parent
.
top
duration
:
500
anchors.right
:
parent
.
right
easing.type
:
Easing
.
OutQuad
anchors.left
:
root
.
isUiPortrait
?
parent
.
left
:
toolBar
.
right
}
anchors.bottom
:
parent
.
bottom
property
real
panelSize
:
0
property
real
previousImSize
:
0
property
real
imSize
:
!
root
.
applicationActive
?
0
:
(
isUiPortrait
?
(
root
.
_transpose
?
Qt
.
inputMethod
.
keyboardRectangle
.
width
:
Qt
.
inputMethod
.
keyboardRectangle
.
height
)
:
(
root
.
_transpose
?
Qt
.
inputMethod
.
keyboardRectangle
.
height
:
Qt
.
inputMethod
.
keyboardRectangle
.
width
))
onImSizeChanged
:
{
if
(
imSize
<=
0
&&
previousImSize
>
0
)
{
imShowAnimation
.
stop
()
imHideAnimation
.
start
()
}
else
if
(
imSize
>
0
&&
previousImSize
<=
0
)
{
imHideAnimation
.
stop
()
imShowAnimation
.
to
=
imSize
imShowAnimation
.
start
()
}
else
{
panelSize
=
imSize
}
}
previousImSize
=
imSize
}
}
popTransition
:
Component
{
StackViewTransition
{
clip
:
true
PropertyAnimation
{
Component.onCompleted
:
{
target
:
enterItem
stackInitialized
=
true
property
:
"
x
"
from
:
-
target
.
width
to
:
0
duration
:
500
easing.type
:
Easing
.
OutQuad
}
PropertyAnimation
{
target
:
exitItem
property
:
"
x
"
from
:
0
to
:
target
.
width
duration
:
500
easing.type
:
Easing
.
OutQuad
}
}
}
}
//IMPORTANT: this property makes it so that at app startup we wait for the initial page to be pushed
//before determining the initial ui orientation (see the states logic below)
//If we don't use this, the orientation will change first time based on NemoWindow's allowedOrientation,
//and the second time based on the allowedOrientations of the initialItem of the stack.
//Using this property avoids that, and make the UI directly start in the correct orientation
//TODO: find a cleaner way to do it (if there's any)
property
bool
stackInitialized
:
false
onStackInitializedChanged
:
if
(
stackInitialized
)
{
//set Screen.orientation as default, if allowed
if
(
root
.
isOrientationAllowed
(
Screen
.
orientation
))
{
contentArea
.
filteredOrientation
=
Screen
.
orientation
}
else
{
//let the window handle it, it will fall back to an allowed orientation
root
.
fallbackToAnAllowedOrientation
()
}
}
}
//this has to be a function, property won't work inside onCurrentItemChanged, as the property binding hasn't been updated yet there
}
//(hence we'd be using the old currentItem)
function
_isCurrentItemNemoPage
()
{
return
currentItem
&&
currentItem
.
hasOwnProperty
(
"
__isNemoPage
"
)
}
Header
{
//update orientation constraints when a Page is pushed/popped
id
:
toolBar
onCurrentItemChanged
:
{
stackView
:
root
.
pageStack
if
(
_isCurrentItemNemoPage
())
appWindow
:
root
root
.
orientationConstraintsChanged
()
}
//used to animate the dimmer when pages are pushed/popped (see Header's QML code)
//This properties are accessible for free by the Page via Stack.view.<property>
property
alias
__dimmer
:
headerDimmerContainer
readonly
property
int
orientation
:
contentArea
.
uiOrientation
}
property
alias
allowedOrientations
:
root
.
allowedOrientations
property
alias
orientationTransitionRunning
:
contentArea
.
orientationTransitionRunning
Item
{
Connections
{
//This item handles the rotation of the dimmer.
id
:
pageConn
//All this because QML doesn't have a horizontal gradient (unless you import GraphicalEffects)
target
:
stackView
.
_isCurrentItemNemoPage
()
?
stackView
.
currentItem
:
null
//and having a container which doesn't rotate but just resizes makes it easier to rotate its inner
onAllowedOrientationsChanged
:
root
.
orientationConstraintsChanged
()
//child
id
:
headerDimmerContainer
//README: Don't use AnchorChanges for this item!
//Reason: state changes disable bindings while the transition from one state to another is running.
//This causes the dimmer not to follow the drawer when the drawer is closed right before the orientation change
anchors.top
:
isUiPortrait
?
toolBar
.
bottom
:
parent
.
top
anchors.left
:
isUiPortrait
?
parent
.
left
:
toolBar
.
right
anchors.right
:
isUiPortrait
?
parent
.
right
:
undefined
anchors.bottom
:
isUiPortrait
?
undefined
:
parent
.
bottom
//we only set the size in one orientation, the anchors will take care of the other
width
:
if
(
!
isUiPortrait
)
Theme
.
itemHeightExtraSmall
/
2
height
:
if
(
isUiPortrait
)
Theme
.
itemHeightExtraSmall
/
2
//MAKE SURE THAT THE HEIGHT SPECIFIED BY THE THEME IS AN EVEN NUMBER, TO AVOID ROUNDING ERRORS IN THE LAYOUT
Rectangle
{
id
:
headerDimmer
anchors.centerIn
:
parent
gradient
:
Gradient
{
GradientStop
{
position
:
0
;
color
:
Theme
.
backgroundColor
}
GradientStop
{
position
:
1
;
color
:
"
transparent
"
}
}
}
}
}
Item
{
delegate
:
StackViewDelegate
{
id
:
orientationState
pushTransition
:
Component
{
StackViewTransition
{
state
:
'
Unanimated
'
PropertyAnimation
{
target
:
enterItem
states
:
[
property
:
"
x
"
State
{
from
:
target
.
width
name
:
'
Unanimated
'
to
:
0
when
:
!
stackView
||
!
stackInitialized
duration
:
500
},
easing.type
:
Easing
.
OutQuad
State
{
}
name
:
'
Portrait
'
PropertyAnimation
{
when
:
contentArea
.
filteredOrientation
===
Qt
.
PortraitOrientation
// && stackInitialized
target
:
exitItem
PropertyChanges
{
property
:
"
x
"
target
:
contentArea
from
:
0
restoreEntryValues
:
false
to
:
-
target
.
width
width
:
_horizontalDimension
duration
:
500
height
:
_verticalDimension
easing.type
:
Easing
.
OutQuad
rotation
:
0
}
uiOrientation
:
Qt
.
PortraitOrientation
}
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
width
rotation
:
0
}
},
State
{
name
:
'
Landscape
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
LandscapeOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_verticalDimension
height
:
_horizontalDimension
rotation
:
90
uiOrientation
:
Qt
.
LandscapeOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
height
rotation
:
-
90
}
},
State
{
name
:
'
PortraitInverted
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
InvertedPortraitOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_horizontalDimension
height
:
_verticalDimension
rotation
:
180
uiOrientation
:
Qt
.
InvertedPortraitOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
width
rotation
:
0
}
},
State
{
name
:
'
LandscapeInverted
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
InvertedLandscapeOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_verticalDimension
height
:
_horizontalDimension
rotation
:
270
uiOrientation
:
Qt
.
InvertedLandscapeOrientation
}
}
PropertyChanges
{
popTransition
:
Component
{
target
:
headerDimmer
StackViewTransition
{
height
:
Theme
.
itemHeightExtraSmall
/
2
PropertyAnimation
{
width
:
parent
.
height
target
:
enterItem
rotation
:
-
90
property
:
"
x
"
from
:
-
target
.
width
to
:
0
duration
:
500
easing.type
:
Easing
.
OutQuad
}
PropertyAnimation
{
target
:
exitItem
property
:
"
x
"
from
:
0
to
:
target
.
width
duration
:
500
easing.type
:
Easing
.
OutQuad
}
}
}
}
}
]
property
Transition
defaultTransition
:
Transition
{
}
to
:
'
Portrait,Landscape,PortraitInverted,LandscapeInverted
'
from
:
'
Portrait,Landscape,PortraitInverted,LandscapeInverted
'
SequentialAnimation
{
SequentialAnimation
{
PropertyAction
{
id
:
imHideAnimation
target
:
contentArea
PauseAnimation
{
property
:
'
orientationTransitionRunning
'
duration
:
200
value
:
true
}
}
NumberAnimation
{
NumberAnimation
{
target
:
contentArea
target
:
stackView
property
:
'
opacity
'
property
:
'
panelSize
'
to
:
0
to
:
0
duration
:
150
duration
:
200
easing.type
:
Easing
.
InOutQuad
}
}
PropertyAction
{
}
target
:
contentArea
properties
:
'
width,height,rotation,uiOrientation
'
NumberAnimation
{
}
id
:
imShowAnimation
AnchorAnimation
{
target
:
stackView
duration
:
0
property
:
'
panelSize
'
}
duration
:
200
PropertyAction
{
easing.type
:
Easing
.
InOutQuad
target
:
headerDimmer
}
properties
:
'
width,height,rotation
'
}
Header
{
id
:
toolBar
stackView
:
root
.
pageStack
appWindow
:
root
//used to animate the dimmer when pages are pushed/popped (see Header's QML code)
property
alias
__dimmer
:
headerDimmerContainer
}
Item
{
//This item handles the rotation of the dimmer.
//All this because QML doesn't have a horizontal gradient (unless you import GraphicalEffects)
//and having a container which doesn't rotate but just resizes makes it easier to rotate its inner
//child
id
:
headerDimmerContainer
//README: Don't use AnchorChanges for this item!
//Reason: state changes disable bindings while the transition from one state to another is running.
//This causes the dimmer not to follow the drawer when the drawer is closed right before the orientation change
anchors.top
:
isUiPortrait
?
toolBar
.
bottom
:
parent
.
top
anchors.left
:
isUiPortrait
?
parent
.
left
:
toolBar
.
right
anchors.right
:
isUiPortrait
?
parent
.
right
:
undefined
anchors.bottom
:
isUiPortrait
?
undefined
:
parent
.
bottom
//we only set the size in one orientation, the anchors will take care of the other
width
:
if
(
!
isUiPortrait
)
Theme
.
itemHeightExtraSmall
/
2
height
:
if
(
isUiPortrait
)
Theme
.
itemHeightExtraSmall
/
2
//MAKE SURE THAT THE HEIGHT SPECIFIED BY THE THEME IS AN EVEN NUMBER, TO AVOID ROUNDING ERRORS IN THE LAYOUT
Rectangle
{
id
:
headerDimmer
anchors.centerIn
:
parent
gradient
:
Gradient
{
GradientStop
{
position
:
0
;
color
:
Theme
.
backgroundColor
}
GradientStop
{
position
:
1
;
color
:
"
transparent
"
}
}
}
NumberAnimation
{
}
target
:
contentArea
}
property
:
'
opacity
'
to
:
1
Item
{
duration
:
150
id
:
orientationState
state
:
'
Unanimated
'
states
:
[
State
{
name
:
'
Unanimated
'
when
:
!
stackView
||
!
stackInitialized
},
State
{
name
:
'
Portrait
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
PortraitOrientation
// && stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_horizontalDimension
height
:
_verticalDimension
rotation
:
0
uiOrientation
:
Qt
.
PortraitOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
width
rotation
:
0
}
AnchorChanges
{
target
:
clipping
anchors.top
:
parent
.
top
anchors.left
:
parent
.
left
anchors.right
:
undefined
anchors.bottom
:
undefined
}
},
State
{
name
:
'
Landscape
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
LandscapeOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_verticalDimension
height
:
_horizontalDimension
rotation
:
90
uiOrientation
:
Qt
.
LandscapeOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
height
rotation
:
-
90
}
AnchorChanges
{
target
:
clipping
anchors.top
:
undefined
anchors.left
:
undefined
anchors.right
:
parent
.
right
anchors.bottom
:
parent
.
bottom
}
},
State
{
name
:
'
PortraitInverted
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
InvertedPortraitOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_horizontalDimension
height
:
_verticalDimension
rotation
:
180
uiOrientation
:
Qt
.
InvertedPortraitOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
width
rotation
:
0
}
AnchorChanges
{
target
:
clipping
anchors.top
:
undefined
anchors.left
:
undefined
anchors.right
:
parent
.
right
anchors.bottom
:
parent
.
bottom
}
},
State
{
name
:
'
LandscapeInverted
'
when
:
contentArea
.
filteredOrientation
===
Qt
.
InvertedLandscapeOrientation
//&& stackInitialized
PropertyChanges
{
target
:
contentArea
restoreEntryValues
:
false
width
:
_verticalDimension
height
:
_horizontalDimension
rotation
:
270
uiOrientation
:
Qt
.
InvertedLandscapeOrientation
}
PropertyChanges
{
target
:
headerDimmer
height
:
Theme
.
itemHeightExtraSmall
/
2
width
:
parent
.
height
rotation
:
-
90
}
AnchorChanges
{
target
:
clipping
anchors.top
:
undefined
anchors.left
:
parent
.
left
anchors.right
:
undefined
anchors.bottom
:
parent
.
bottom
}
}
}
PropertyAction
{
]
target
:
contentArea
property
:
'
orientationTransitionRunning
'
property
Transition
defaultTransition
:
Transition
{
value
:
false
to
:
'
Portrait,Landscape,PortraitInverted,LandscapeInverted
'
from
:
'
Portrait,Landscape,PortraitInverted,LandscapeInverted
'
SequentialAnimation
{
PropertyAction
{
target
:
contentArea
property
:
'
orientationTransitionRunning
'
value
:
true
}
NumberAnimation
{
target
:
contentArea
property
:
'
opacity
'
to
:
0
duration
:
150
}
PropertyAction
{
target
:
contentArea
properties
:
'
width,height,rotation,uiOrientation
'
}
AnchorAnimation
{
duration
:
0
}
PropertyAction
{
target
:
headerDimmer
properties
:
'
width,height,rotation
'
}
NumberAnimation
{
target
:
contentArea
property
:
'
opacity
'
to
:
1
duration
:
150
}
PropertyAction
{
target
:
contentArea
property
:
'
orientationTransitionRunning
'
value
:
false
}
}
}
}
}
}
Component.onCompleted
:
{
Component.onCompleted
:
{
if
(
transitions
.
length
===
0
)
{
if
(
transitions
.
length
===
0
)
{
transitions
=
[
defaultTransition
]
transitions
=
[
defaultTransition
]
}
}
}
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment