Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qgroundcontrol
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
Valentin Platzgummer
qgroundcontrol
Commits
6ebae0ae
Unverified
Commit
6ebae0ae
authored
Jul 31, 2019
by
Gus Grubba
Committed by
GitHub
Jul 31, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7649 from mavlink/stdComboBox
Std ComboBox
parents
2de904b7
4b215098
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
45 additions
and
506 deletions
+45
-506
custom.qrc
custom-example/custom.qrc
+0
-1
CustomComboBox.qml
custom-example/res/Custom/Widgets/CustomComboBox.qml
+0
-252
qmldir
custom-example/res/Custom/Widgets/qmldir
+0
-1
SimpleItemEditor.qml
src/PlanView/SimpleItemEditor.qml
+1
-1
PageView.qml
src/QmlControls/PageView.qml
+1
-1
QGCComboBox.qml
src/QmlControls/QGCComboBox.qml
+41
-249
ScreenTools.qml
src/QmlControls/ScreenTools.qml
+2
-1
No files found.
custom-example/custom.qrc
View file @
6ebae0ae
...
...
@@ -40,7 +40,6 @@
<qresource prefix="Custom/Widgets">
<file alias="Custom/Widgets/CustomArtificialHorizon.qml">res/Custom/Widgets/CustomArtificialHorizon.qml</file>
<file alias="Custom/Widgets/CustomAttitudeWidget.qml">res/Custom/Widgets/CustomAttitudeWidget.qml</file>
<file alias="Custom/Widgets/CustomComboBox.qml">res/Custom/Widgets/CustomComboBox.qml</file>
<file alias="Custom/Widgets/CustomIconButton.qml">res/Custom/Widgets/CustomIconButton.qml</file>
<file alias="Custom/Widgets/CustomOnOffSwitch.qml">res/Custom/Widgets/CustomOnOffSwitch.qml</file>
<file alias="Custom/Widgets/CustomQuickButton.qml">res/Custom/Widgets/CustomQuickButton.qml</file>
...
...
custom-example/res/Custom/Widgets/CustomComboBox.qml
deleted
100644 → 0
View file @
2de904b7
/****************************************************************************
*
* (c) 2009-2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
* @file
* @author Gus Grubba <gus@auterion.com>
*/
import
QtQuick
2.11
import
QtQuick
.
Controls
1.4
import
QtQuick
.
Controls
.
Styles
1.4
import
QGroundControl
.
Controls
1.0
import
QGroundControl
.
Palette
1.0
import
QGroundControl
.
ScreenTools
1.0
Button
{
id
:
combo
property
real
pointSize
:
ScreenTools
.
defaultFontPointSize
///< Point size for button text
property
bool
centeredLabel
:
false
property
alias
model
:
popupItems
.
model
property
alias
textRole
:
popup
.
textRole
property
alias
currentIndex
:
popup
.
__selectedIndex
readonly
property
alias
count
:
popupItems
.
count
readonly
property
alias
currentText
:
popup
.
currentText
property
var
_qgcPal
:
QGCPalette
{
colorGroupEnabled
:
enabled
}
property
int
_verticalPadding
:
Math
.
round
(
ScreenTools
.
defaultFontPixelHeight
*
0.5
)
property
real
_dropImageWidth
:
ScreenTools
.
defaultFontPixelHeight
*
0.5
property
real
_dropImageMargin
:
_dropImageWidth
*
0.5
property
var
__popup
:
popup
signal
activated
(
int
index
)
style
:
ButtonStyle
{
/*! This defines the background of the button. */
background
:
Rectangle
{
implicitWidth
:
Math
.
round
(
ScreenTools
.
defaultFontPixelWidth
*
6
)
implicitHeight
:
Math
.
round
(
ScreenTools
.
defaultFontPixelHeight
)
color
:
Qt
.
rgba
(
0
,
0
,
0
,
0
)
/*
Image {
id: image
width: _dropImageWidth
height: _dropImageWidth
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: _dropImageMargin
anchors.right: parent.right
source: "/custom/img/menu_dropdown.svg"
}
*/
}
/*! This defines the label of the button. */
label
:
Item
{
implicitWidth
:
text
.
implicitWidth
implicitHeight
:
text
.
implicitHeight
baselineOffset
:
text
.
y
+
text
.
baselineOffset
QGCLabel
{
id
:
text
anchors.verticalCenter
:
parent
.
verticalCenter
anchors.horizontalCenter
:
centeredLabel
?
parent
.
horizontalCenter
:
undefined
text
:
control
.
currentText
color
:
"
#FFF
"
font.pointSize
:
combo
.
pointSize
}
}
}
onClicked
:
{
combo
.
focus
=
true
popup
.
toggleShow
()
}
Component.onCompleted
:
{
if
(
currentIndex
===
-
1
)
{
currentIndex
=
0
}
popup
.
resolveTextValue
(
textRole
)
}
function
textAt
(
index
)
{
if
(
index
>=
count
||
index
<
0
)
return
null
;
return
popupItems
.
objectAt
(
index
).
text
;
}
function
find
(
text
)
{
for
(
var
i
=
0
;
i
<
popupItems
.
count
;
++
i
)
{
var
currentString
=
popupItems
.
objectAt
(
i
).
text
if
(
text
===
currentString
)
{
return
i
}
}
return
-
1
}
ExclusiveGroup
{
id
:
eg
}
Menu
{
id
:
popup
__minimumWidth
:
combo
.
width
__visualItem
:
combo
style
:
MenuStyle
{
font.pointSize
:
combo
.
pointSize
font.family
:
ScreenTools
.
normalFontFamily
__labelColor
:
combo
.
_qgcPal
.
buttonText
__selectedLabelColor
:
combo
.
_qgcPal
.
buttonHighlightText
__selectedBackgroundColor
:
combo
.
_qgcPal
.
buttonHighlight
__backgroundColor
:
combo
.
_qgcPal
.
button
__maxPopupHeight
:
600
__menuItemType
:
"
comboboxitem
"
__scrollerStyle
:
ScrollViewStyle
{
}
}
property
string
textRole
:
""
property
bool
showing
:
false
property
string
currentText
:
selectedText
property
string
selectedText
onSelectedTextChanged
:
popup
.
currentText
=
selectedText
on__SelectedIndexChanged
:
{
if
(
__selectedIndex
===
-
1
)
popup
.
currentText
=
""
else
updateSelectedText
()
}
property
int
_y
:
combo
.
height
property
bool
_modelIsArray
:
false
onAboutToShow
:
showing
=
true
onAboutToHide
:
showing
=
false
function
toggleShow
()
{
if
(
popup
.
_popupVisible
)
{
popup
.
__dismissAndDestroy
()
}
else
{
__popup
(
Qt
.
rect
(
0
,
_y
,
0
,
0
),
0
)
}
}
function
resolveTextValue
(
initialTextRole
)
{
if
(
!
model
)
{
return
}
var
get
=
model
[
'
get
'
];
if
(
!
get
&&
popup
.
_modelIsArray
&&
!!
model
[
0
])
{
if
(
model
[
0
].
constructor
!==
String
&&
model
[
0
].
constructor
!==
Number
)
get
=
function
(
i
)
{
return
model
[
i
];
}
}
var
modelMayHaveRoles
=
get
!==
undefined
textRole
=
initialTextRole
if
(
textRole
===
""
&&
modelMayHaveRoles
&&
get
(
0
))
{
// No text role set, check whether model has a suitable role
// If 'text' is found, or there's only one role, pick that.
var
listElement
=
get
(
0
)
var
roleName
=
""
var
roleCount
=
0
for
(
var
role
in
listElement
)
{
if
(
listElement
[
role
].
constructor
===
Function
)
continue
;
if
(
role
===
"
text
"
)
{
roleName
=
role
break
}
else
if
(
!
roleName
)
{
roleName
=
role
}
++
roleCount
}
if
(
roleCount
>
1
&&
roleName
!==
"
text
"
)
{
console
.
warn
(
"
No suitable 'textRole' found for ComboBox.
"
)
}
else
{
textRole
=
roleName
}
}
updateSelectedText
()
}
function
updateSelectedText
()
{
var
selectedItem
if
(
__selectedIndex
!==
-
1
&&
(
selectedItem
=
items
[
__selectedIndex
]))
{
selectedText
=
Qt
.
binding
(
function
()
{
return
selectedItem
.
text
})
if
(
currentText
!==
selectedText
)
// __selectedIndex went form -1 to 0
selectedTextChanged
()
}
}
Instantiator
{
id
:
popupItems
onModelChanged
:
{
popup
.
_modelIsArray
=
!!
model
?
model
.
constructor
===
Array
:
false
popup
.
resolveTextValue
(
popup
.
textRole
)
}
onObjectAdded
:
{
// There is a bug in Instantiator which can cause objects to be added out of order from an index standpoint.
// If not handled correctly this will cause menu items to be added incorrectly due to the way Menu.insertItem works.
//console.log("menu add", index, object.text)
if
(
index
===
popup
.
__selectedIndex
)
{
popup
.
selectedText
=
object
[
"
text
"
]
}
// Find the correct place for menu item. We can't just add at index, due to possible bad ordering
var
insertIndex
=
-
1
for
(
var
i
=
0
;
i
<
popup
.
items
.
length
;
i
++
)
{
//console.log("position search", i, popup.items[i].itemIndex)
if
(
popup
.
items
[
i
].
itemIndex
>
index
)
{
insertIndex
=
i
break
}
}
if
(
insertIndex
===
-
1
)
{
popup
.
insertItem
(
popup
.
items
.
length
,
object
)
}
else
{
//console.log("out of order menu add", index, insertIndex)
popup
.
insertItem
(
insertIndex
,
object
)
}
}
onObjectRemoved
:
popup
.
removeItem
(
object
)
MenuItem
{
text
:
popup
.
textRole
===
''
?
modelData
:
((
popup
.
_modelIsArray
?
modelData
[
popup
.
textRole
]
:
model
[
popup
.
textRole
])
||
''
)
checked
:
index
==
currentIndex
checkable
:
true
exclusiveGroup
:
eg
property
int
itemIndex
:
index
onTriggered
:
{
//console.log("onTriggered", index, currentIndex)
if
(
index
!==
currentIndex
)
{
//console.log("activated", index)
activated
(
index
)
}
}
}
}
}
}
custom-example/res/Custom/Widgets/qmldir
View file @
6ebae0ae
...
...
@@ -2,7 +2,6 @@ Module Custom.Widgets
CustomArtificialHorizon 1.0 CustomArtificialHorizon.qml
CustomAttitudeWidget 1.0 CustomAttitudeWidget.qml
CustomComboBox 1.0 CustomComboBox.qml
CustomIconButton 1.0 CustomIconButton.qml
CustomOnOffSwitch 1.0 CustomOnOffSwitch.qml
CustomQuickButton 1.0 CustomQuickButton.qml
...
...
src/PlanView/SimpleItemEditor.qml
View file @
6ebae0ae
...
...
@@ -92,7 +92,7 @@ Rectangle {
indexModel
:
false
model
:
object
.
enumStrings
fact
:
object
pointSize
:
ScreenTools
.
smallFontPointSize
font.pointSize
:
ScreenTools
.
smallFontPointSize
Layout.column
:
1
Layout.row
:
index
Layout.fillWidth
:
true
...
...
src/QmlControls/PageView.qml
View file @
6ebae0ae
...
...
@@ -27,7 +27,7 @@ Rectangle {
model
:
_instrumentPages
textRole
:
"
title
"
centeredLabel
:
true
pointSize
:
ScreenTools
.
smallFontPointSize
font.pointSize
:
ScreenTools
.
smallFontPointSize
Image
{
anchors.leftMargin
:
_margins
...
...
src/QmlControls/QGCComboBox.qml
View file @
6ebae0ae
import
QtQuick
2.3
import
QtQuick
.
Controls
1.2
import
QtQuick
.
Controls
.
Styles
1.4
import
QGroundControl
.
Palette
1.0
import
QGroundControl
.
ScreenTools
1.0
Button
{
id
:
combo
implicitHeight
:
ScreenTools
.
implicitComboBoxHeight
property
real
pointSize
:
ScreenTools
.
defaultFontPointSize
///< Point size for button text
property
bool
centeredLabel
:
false
property
alias
model
:
popupItems
.
model
property
alias
textRole
:
popup
.
textRole
property
alias
currentIndex
:
popup
.
__selectedIndex
readonly
property
alias
count
:
popupItems
.
count
readonly
property
alias
currentText
:
popup
.
currentText
property
bool
_showBorder
:
_qgcPal
.
globalTheme
===
QGCPalette
.
Light
property
var
_qgcPal
:
QGCPalette
{
colorGroupEnabled
:
enabled
}
property
int
_horizontalPadding
:
ScreenTools
.
defaultFontPixelWidth
property
int
_verticalPadding
:
Math
.
round
(
ScreenTools
.
defaultFontPixelHeight
/
2
)
property
real
_dropImageWidth
:
ScreenTools
.
defaultFontPixelHeight
/
2
property
real
_dropImageMargin
:
_dropImageWidth
/
2
property
var
__popup
:
popup
signal
activated
(
int
index
)
style
:
ButtonStyle
{
/*! The padding between the background and the label components. */
padding
{
top
:
_verticalPadding
bottom
:
_verticalPadding
left
:
_horizontalPadding
right
:
_horizontalPadding
}
/*! This defines the background of the button. */
background
:
Rectangle
{
implicitWidth
:
ScreenTools
.
implicitComboBoxWidth
implicitHeight
:
ScreenTools
.
implicitComboBoxHeight
color
:
control
.
_qgcPal
.
textField
border.width
:
enabled
?
1
:
0
border.color
:
"
#999
"
QGCColoredImage
{
id
:
image
width
:
_dropImageWidth
height
:
_dropImageWidth
anchors.verticalCenter
:
parent
.
verticalCenter
anchors.rightMargin
:
_dropImageMargin
anchors.right
:
parent
.
right
source
:
"
/qmlimages/arrow-down.png
"
color
:
control
.
_qgcPal
.
textFieldText
}
}
/*! This defines the label of the button. */
label
:
Item
{
implicitWidth
:
text
.
implicitWidth
+
_dropImageWidth
implicitHeight
:
text
.
implicitHeight
baselineOffset
:
text
.
y
+
text
.
baselineOffset
QGCLabel
{
id
:
text
anchors.verticalCenter
:
parent
.
verticalCenter
anchors.horizontalCenter
:
centeredLabel
?
parent
.
horizontalCenter
:
undefined
text
:
control
.
currentText
color
:
control
.
_qgcPal
.
textFieldText
font.pointSize
:
pointSize
}
}
}
onClicked
:
{
combo
.
focus
=
true
popup
.
toggleShow
()
}
Component.onCompleted
:
{
if
(
currentIndex
===
-
1
)
{
currentIndex
=
0
}
popup
.
resolveTextValue
(
textRole
)
/****************************************************************************
*
* (c) 2009-2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
* @file
* @author Gus Grubba <gus@auterion.com>
*/
import
QtQuick
2.11
import
QtQuick
.
Controls
2.4
import
QtQuick
.
Layouts
1.11
import
QGroundControl
.
Controls
1.0
import
QGroundControl
.
Palette
1.0
import
QGroundControl
.
ScreenTools
1.0
ComboBox
{
id
:
control
padding
:
ScreenTools
.
comboBoxPadding
property
bool
centeredLabel
:
false
background
:
Rectangle
{
implicitWidth
:
ScreenTools
.
implicitComboBoxWidth
implicitHeight
:
ScreenTools
.
implicitComboBoxHeight
color
:
qgcPal
.
textField
border.width
:
enabled
?
1
:
0
border.color
:
"
#999
"
}
function
textAt
(
index
)
{
if
(
index
>=
count
||
index
<
0
)
return
null
;
return
popupItems
.
objectAt
(
index
).
text
;
}
function
find
(
text
)
{
for
(
var
i
=
0
;
i
<
popupItems
.
count
;
++
i
)
{
var
currentString
=
popupItems
.
objectAt
(
i
).
text
if
(
text
===
currentString
)
{
return
i
}
}
return
-
1
}
ExclusiveGroup
{
id
:
eg
}
QGCMenu
{
id
:
popup
__minimumWidth
:
combo
.
width
__visualItem
:
combo
style
:
MenuStyle
{
font.pointSize
:
ScreenTools
.
defaultFontPointSize
font.family
:
ScreenTools
.
normalFontFamily
__labelColor
:
combo
.
_qgcPal
.
buttonText
__selectedLabelColor
:
combo
.
_qgcPal
.
buttonHighlightText
__selectedBackgroundColor
:
combo
.
_qgcPal
.
buttonHighlight
__backgroundColor
:
combo
.
_qgcPal
.
button
__maxPopupHeight
:
600
__menuItemType
:
"
comboboxitem
"
__scrollerStyle
:
ScrollViewStyle
{
}
}
property
string
textRole
:
""
property
bool
showing
:
false
property
string
currentText
:
selectedText
property
string
selectedText
onSelectedTextChanged
:
popup
.
currentText
=
selectedText
on__SelectedIndexChanged
:
{
if
(
__selectedIndex
===
-
1
)
popup
.
currentText
=
""
else
updateSelectedText
()
}
property
int
_y
:
combo
.
height
property
bool
_modelIsArray
:
false
onAboutToShow
:
showing
=
true
onAboutToHide
:
showing
=
false
function
toggleShow
()
{
if
(
popup
.
_popupVisible
)
{
popup
.
__dismissAndDestroy
()
}
else
{
__popup
(
Qt
.
rect
(
0
,
_y
,
0
,
0
),
0
)
}
}
function
resolveTextValue
(
initialTextRole
)
{
if
(
!
model
)
{
return
}
var
get
=
model
[
'
get
'
];
if
(
!
get
&&
popup
.
_modelIsArray
&&
!!
model
[
0
])
{
if
(
model
[
0
].
constructor
!==
String
&&
model
[
0
].
constructor
!==
Number
)
get
=
function
(
i
)
{
return
model
[
i
];
}
}
var
modelMayHaveRoles
=
get
!==
undefined
textRole
=
initialTextRole
if
(
textRole
===
""
&&
modelMayHaveRoles
&&
get
(
0
))
{
// No text role set, check whether model has a suitable role
// If 'text' is found, or there's only one role, pick that.
var
listElement
=
get
(
0
)
var
roleName
=
""
var
roleCount
=
0
for
(
var
role
in
listElement
)
{
if
(
listElement
[
role
].
constructor
===
Function
)
continue
;
if
(
role
===
"
text
"
)
{
roleName
=
role
break
}
else
if
(
!
roleName
)
{
roleName
=
role
}
++
roleCount
}
if
(
roleCount
>
1
&&
roleName
!==
"
text
"
)
{
console
.
warn
(
"
No suitable 'textRole' found for ComboBox.
"
)
}
else
{
textRole
=
roleName
}
}
updateSelectedText
()
}
function
updateSelectedText
()
{
var
selectedItem
if
(
__selectedIndex
!==
-
1
&&
(
selectedItem
=
items
[
__selectedIndex
]))
{
selectedText
=
Qt
.
binding
(
function
()
{
return
selectedItem
.
text
})
if
(
currentText
!==
selectedText
)
// __selectedIndex went form -1 to 0
selectedTextChanged
()
}
}
Instantiator
{
id
:
popupItems
onModelChanged
:
{
popup
.
_modelIsArray
=
!!
model
?
model
.
constructor
===
Array
:
false
popup
.
resolveTextValue
(
popup
.
textRole
)
}
onObjectAdded
:
{
// There is a bug in Instantiator which can cause objects to be added out of order from an index standpoint.
// If not handled correctly this will cause menu items to be added incorrectly due to the way Menu.insertItem works.
//console.log("menu add", index, object.text)
if
(
index
===
popup
.
__selectedIndex
)
{
popup
.
selectedText
=
object
[
"
text
"
]
}
// Find the correct place for menu item. We can't just add at index, due to possible bad ordering
var
insertIndex
=
-
1
for
(
var
i
=
0
;
i
<
popup
.
items
.
length
;
i
++
)
{
//console.log("position search", i, popup.items[i].itemIndex)
if
(
popup
.
items
[
i
].
itemIndex
>
index
)
{
insertIndex
=
i
break
}
}
if
(
insertIndex
===
-
1
)
{
popup
.
insertItem
(
popup
.
items
.
length
,
object
)
}
else
{
//console.log("out of order menu add", index, insertIndex)
popup
.
insertItem
(
insertIndex
,
object
)
}
}
onObjectRemoved
:
popup
.
removeItem
(
object
)
QGCMenuItem
{
text
:
popup
.
textRole
===
''
?
modelData
:
((
popup
.
_modelIsArray
?
modelData
[
popup
.
textRole
]
:
model
[
popup
.
textRole
])
||
''
)
checked
:
index
==
currentIndex
checkable
:
true
exclusiveGroup
:
eg
property
int
itemIndex
:
index
onTriggered
:
{
//console.log("onTriggered", index, currentIndex)
if
(
index
!==
currentIndex
)
{
//console.log("activated", index)
activated
(
index
)
}
}
}
/*! This defines the label of the button. */
contentItem
:
Item
{
implicitWidth
:
text
.
implicitWidth
implicitHeight
:
text
.
implicitHeight
QGCLabel
{
id
:
text
anchors.verticalCenter
:
parent
.
verticalCenter
anchors.horizontalCenter
:
centeredLabel
?
parent
.
horizontalCenter
:
undefined
text
:
control
.
currentText
color
:
qgcPal
.
textFieldText
}
}
}
src/QmlControls/ScreenTools.qml
View file @
6ebae0ae
...
...
@@ -75,7 +75,7 @@ Item {
property
bool
isDebug
:
ScreenToolsController
.
isDebug
property
bool
isMac
:
ScreenToolsController
.
isMacOS
property
bool
isTinyScreen
:
(
Screen
.
width
/
realPixelDensity
)
<
120
// 120mm
property
bool
isShortScreen
:
ScreenToolsController
.
isMobile
&&
((
Screen
.
height
/
Screen
.
width
)
<
0.6
)
// Nexus 7 for example
property
bool
isShortScreen
:
((
Screen
.
height
/
realPixelDensity
)
<
120
)
||
(
ScreenToolsController
.
isMobile
&&
((
Screen
.
height
/
Screen
.
width
)
<
0.6
))
property
bool
isHugeScreen
:
(
Screen
.
width
/
realPixelDensity
)
>=
(
23.5
*
25.4
)
// 27" monitor
property
bool
isSerialAvailable
:
ScreenToolsController
.
isSerialAvailable
...
...
@@ -90,6 +90,7 @@ Item {
property
real
implicitTextFieldHeight
:
Math
.
round
(
defaultFontPixelHeight
*
(
isMobile
?
2.0
:
1.6
))
property
real
implicitComboBoxHeight
:
Math
.
round
(
defaultFontPixelHeight
*
(
isMobile
?
2.0
:
1.6
))
property
real
implicitComboBoxWidth
:
Math
.
round
(
defaultFontPixelWidth
*
(
isMobile
?
7.0
:
5.0
))
property
real
comboBoxPadding
:
Math
.
round
(
defaultFontPixelWidth
*
(
isShortScreen
?
1
:
0.5
))
property
real
implicitSliderHeight
:
isMobile
?
Math
.
max
(
defaultFontPixelHeight
,
minTouchPixels
)
:
defaultFontPixelHeight
// It's not possible to centralize an even number of pixels, checkBoxIndicatorSize should be an odd number to allow centralization
property
real
checkBoxIndicatorSize
:
2
*
Math
.
floor
(
defaultFontPixelHeight
*
(
isMobile
?
1.5
:
1.0
)
/
2
)
+
1
...
...
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