First working version
							
								
								
									
										427
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,427 @@ | ||||||
|  | Attribution-ShareAlike 4.0 International | ||||||
|  | 
 | ||||||
|  | ======================================================================= | ||||||
|  | 
 | ||||||
|  | Creative Commons Corporation ("Creative Commons") is not a law firm and | ||||||
|  | does not provide legal services or legal advice. Distribution of | ||||||
|  | Creative Commons public licenses does not create a lawyer-client or | ||||||
|  | other relationship. Creative Commons makes its licenses and related | ||||||
|  | information available on an "as-is" basis. Creative Commons gives no | ||||||
|  | warranties regarding its licenses, any material licensed under their | ||||||
|  | terms and conditions, or any related information. Creative Commons | ||||||
|  | disclaims all liability for damages resulting from their use to the | ||||||
|  | fullest extent possible. | ||||||
|  | 
 | ||||||
|  | Using Creative Commons Public Licenses | ||||||
|  | 
 | ||||||
|  | Creative Commons public licenses provide a standard set of terms and | ||||||
|  | conditions that creators and other rights holders may use to share | ||||||
|  | original works of authorship and other material subject to copyright | ||||||
|  | and certain other rights specified in the public license below. The | ||||||
|  | following considerations are for informational purposes only, are not | ||||||
|  | exhaustive, and do not form part of our licenses. | ||||||
|  | 
 | ||||||
|  |      Considerations for licensors: Our public licenses are | ||||||
|  |      intended for use by those authorized to give the public | ||||||
|  |      permission to use material in ways otherwise restricted by | ||||||
|  |      copyright and certain other rights. Our licenses are | ||||||
|  |      irrevocable. Licensors should read and understand the terms | ||||||
|  |      and conditions of the license they choose before applying it. | ||||||
|  |      Licensors should also secure all rights necessary before | ||||||
|  |      applying our licenses so that the public can reuse the | ||||||
|  |      material as expected. Licensors should clearly mark any | ||||||
|  |      material not subject to the license. This includes other CC- | ||||||
|  |      licensed material, or material used under an exception or | ||||||
|  |      limitation to copyright. More considerations for licensors: | ||||||
|  | 	wiki.creativecommons.org/Considerations_for_licensors | ||||||
|  | 
 | ||||||
|  |      Considerations for the public: By using one of our public | ||||||
|  |      licenses, a licensor grants the public permission to use the | ||||||
|  |      licensed material under specified terms and conditions. If | ||||||
|  |      the licensor's permission is not necessary for any reason--for | ||||||
|  |      example, because of any applicable exception or limitation to | ||||||
|  |      copyright--then that use is not regulated by the license. Our | ||||||
|  |      licenses grant only permissions under copyright and certain | ||||||
|  |      other rights that a licensor has authority to grant. Use of | ||||||
|  |      the licensed material may still be restricted for other | ||||||
|  |      reasons, including because others have copyright or other | ||||||
|  |      rights in the material. A licensor may make special requests, | ||||||
|  |      such as asking that all changes be marked or described. | ||||||
|  |      Although not required by our licenses, you are encouraged to | ||||||
|  |      respect those requests where reasonable. More_considerations | ||||||
|  |      for the public: | ||||||
|  | 	wiki.creativecommons.org/Considerations_for_licensees | ||||||
|  | 
 | ||||||
|  | ======================================================================= | ||||||
|  | 
 | ||||||
|  | Creative Commons Attribution-ShareAlike 4.0 International Public | ||||||
|  | License | ||||||
|  | 
 | ||||||
|  | By exercising the Licensed Rights (defined below), You accept and agree | ||||||
|  | to be bound by the terms and conditions of this Creative Commons | ||||||
|  | Attribution-ShareAlike 4.0 International Public License ("Public | ||||||
|  | License"). To the extent this Public License may be interpreted as a | ||||||
|  | contract, You are granted the Licensed Rights in consideration of Your | ||||||
|  | acceptance of these terms and conditions, and the Licensor grants You | ||||||
|  | such rights in consideration of benefits the Licensor receives from | ||||||
|  | making the Licensed Material available under these terms and | ||||||
|  | conditions. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 1 -- Definitions. | ||||||
|  | 
 | ||||||
|  |   a. Adapted Material means material subject to Copyright and Similar | ||||||
|  |      Rights that is derived from or based upon the Licensed Material | ||||||
|  |      and in which the Licensed Material is translated, altered, | ||||||
|  |      arranged, transformed, or otherwise modified in a manner requiring | ||||||
|  |      permission under the Copyright and Similar Rights held by the | ||||||
|  |      Licensor. For purposes of this Public License, where the Licensed | ||||||
|  |      Material is a musical work, performance, or sound recording, | ||||||
|  |      Adapted Material is always produced where the Licensed Material is | ||||||
|  |      synched in timed relation with a moving image. | ||||||
|  | 
 | ||||||
|  |   b. Adapter's License means the license You apply to Your Copyright | ||||||
|  |      and Similar Rights in Your contributions to Adapted Material in | ||||||
|  |      accordance with the terms and conditions of this Public License. | ||||||
|  | 
 | ||||||
|  |   c. BY-SA Compatible License means a license listed at | ||||||
|  |      creativecommons.org/compatiblelicenses, approved by Creative | ||||||
|  |      Commons as essentially the equivalent of this Public License. | ||||||
|  | 
 | ||||||
|  |   d. Copyright and Similar Rights means copyright and/or similar rights | ||||||
|  |      closely related to copyright including, without limitation, | ||||||
|  |      performance, broadcast, sound recording, and Sui Generis Database | ||||||
|  |      Rights, without regard to how the rights are labeled or | ||||||
|  |      categorized. For purposes of this Public License, the rights | ||||||
|  |      specified in Section 2(b)(1)-(2) are not Copyright and Similar | ||||||
|  |      Rights. | ||||||
|  | 
 | ||||||
|  |   e. Effective Technological Measures means those measures that, in the | ||||||
|  |      absence of proper authority, may not be circumvented under laws | ||||||
|  |      fulfilling obligations under Article 11 of the WIPO Copyright | ||||||
|  |      Treaty adopted on December 20, 1996, and/or similar international | ||||||
|  |      agreements. | ||||||
|  | 
 | ||||||
|  |   f. Exceptions and Limitations means fair use, fair dealing, and/or | ||||||
|  |      any other exception or limitation to Copyright and Similar Rights | ||||||
|  |      that applies to Your use of the Licensed Material. | ||||||
|  | 
 | ||||||
|  |   g. License Elements means the license attributes listed in the name | ||||||
|  |      of a Creative Commons Public License. The License Elements of this | ||||||
|  |      Public License are Attribution and ShareAlike. | ||||||
|  | 
 | ||||||
|  |   h. Licensed Material means the artistic or literary work, database, | ||||||
|  |      or other material to which the Licensor applied this Public | ||||||
|  |      License. | ||||||
|  | 
 | ||||||
|  |   i. Licensed Rights means the rights granted to You subject to the | ||||||
|  |      terms and conditions of this Public License, which are limited to | ||||||
|  |      all Copyright and Similar Rights that apply to Your use of the | ||||||
|  |      Licensed Material and that the Licensor has authority to license. | ||||||
|  | 
 | ||||||
|  |   j. Licensor means the individual(s) or entity(ies) granting rights | ||||||
|  |      under this Public License. | ||||||
|  | 
 | ||||||
|  |   k. Share means to provide material to the public by any means or | ||||||
|  |      process that requires permission under the Licensed Rights, such | ||||||
|  |      as reproduction, public display, public performance, distribution, | ||||||
|  |      dissemination, communication, or importation, and to make material | ||||||
|  |      available to the public including in ways that members of the | ||||||
|  |      public may access the material from a place and at a time | ||||||
|  |      individually chosen by them. | ||||||
|  | 
 | ||||||
|  |   l. Sui Generis Database Rights means rights other than copyright | ||||||
|  |      resulting from Directive 96/9/EC of the European Parliament and of | ||||||
|  |      the Council of 11 March 1996 on the legal protection of databases, | ||||||
|  |      as amended and/or succeeded, as well as other essentially | ||||||
|  |      equivalent rights anywhere in the world. | ||||||
|  | 
 | ||||||
|  |   m. You means the individual or entity exercising the Licensed Rights | ||||||
|  |      under this Public License. Your has a corresponding meaning. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 2 -- Scope. | ||||||
|  | 
 | ||||||
|  |   a. License grant. | ||||||
|  | 
 | ||||||
|  |        1. Subject to the terms and conditions of this Public License, | ||||||
|  |           the Licensor hereby grants You a worldwide, royalty-free, | ||||||
|  |           non-sublicensable, non-exclusive, irrevocable license to | ||||||
|  |           exercise the Licensed Rights in the Licensed Material to: | ||||||
|  | 
 | ||||||
|  |             a. reproduce and Share the Licensed Material, in whole or | ||||||
|  |                in part; and | ||||||
|  | 
 | ||||||
|  |             b. produce, reproduce, and Share Adapted Material. | ||||||
|  | 
 | ||||||
|  |        2. Exceptions and Limitations. For the avoidance of doubt, where | ||||||
|  |           Exceptions and Limitations apply to Your use, this Public | ||||||
|  |           License does not apply, and You do not need to comply with | ||||||
|  |           its terms and conditions. | ||||||
|  | 
 | ||||||
|  |        3. Term. The term of this Public License is specified in Section | ||||||
|  |           6(a). | ||||||
|  | 
 | ||||||
|  |        4. Media and formats; technical modifications allowed. The | ||||||
|  |           Licensor authorizes You to exercise the Licensed Rights in | ||||||
|  |           all media and formats whether now known or hereafter created, | ||||||
|  |           and to make technical modifications necessary to do so. The | ||||||
|  |           Licensor waives and/or agrees not to assert any right or | ||||||
|  |           authority to forbid You from making technical modifications | ||||||
|  |           necessary to exercise the Licensed Rights, including | ||||||
|  |           technical modifications necessary to circumvent Effective | ||||||
|  |           Technological Measures. For purposes of this Public License, | ||||||
|  |           simply making modifications authorized by this Section 2(a) | ||||||
|  |           (4) never produces Adapted Material. | ||||||
|  | 
 | ||||||
|  |        5. Downstream recipients. | ||||||
|  | 
 | ||||||
|  |             a. Offer from the Licensor -- Licensed Material. Every | ||||||
|  |                recipient of the Licensed Material automatically | ||||||
|  |                receives an offer from the Licensor to exercise the | ||||||
|  |                Licensed Rights under the terms and conditions of this | ||||||
|  |                Public License. | ||||||
|  | 
 | ||||||
|  |             b. Additional offer from the Licensor -- Adapted Material. | ||||||
|  |                Every recipient of Adapted Material from You | ||||||
|  |                automatically receives an offer from the Licensor to | ||||||
|  |                exercise the Licensed Rights in the Adapted Material | ||||||
|  |                under the conditions of the Adapter's License You apply. | ||||||
|  | 
 | ||||||
|  |             c. No downstream restrictions. You may not offer or impose | ||||||
|  |                any additional or different terms or conditions on, or | ||||||
|  |                apply any Effective Technological Measures to, the | ||||||
|  |                Licensed Material if doing so restricts exercise of the | ||||||
|  |                Licensed Rights by any recipient of the Licensed | ||||||
|  |                Material. | ||||||
|  | 
 | ||||||
|  |        6. No endorsement. Nothing in this Public License constitutes or | ||||||
|  |           may be construed as permission to assert or imply that You | ||||||
|  |           are, or that Your use of the Licensed Material is, connected | ||||||
|  |           with, or sponsored, endorsed, or granted official status by, | ||||||
|  |           the Licensor or others designated to receive attribution as | ||||||
|  |           provided in Section 3(a)(1)(A)(i). | ||||||
|  | 
 | ||||||
|  |   b. Other rights. | ||||||
|  | 
 | ||||||
|  |        1. Moral rights, such as the right of integrity, are not | ||||||
|  |           licensed under this Public License, nor are publicity, | ||||||
|  |           privacy, and/or other similar personality rights; however, to | ||||||
|  |           the extent possible, the Licensor waives and/or agrees not to | ||||||
|  |           assert any such rights held by the Licensor to the limited | ||||||
|  |           extent necessary to allow You to exercise the Licensed | ||||||
|  |           Rights, but not otherwise. | ||||||
|  | 
 | ||||||
|  |        2. Patent and trademark rights are not licensed under this | ||||||
|  |           Public License. | ||||||
|  | 
 | ||||||
|  |        3. To the extent possible, the Licensor waives any right to | ||||||
|  |           collect royalties from You for the exercise of the Licensed | ||||||
|  |           Rights, whether directly or through a collecting society | ||||||
|  |           under any voluntary or waivable statutory or compulsory | ||||||
|  |           licensing scheme. In all other cases the Licensor expressly | ||||||
|  |           reserves any right to collect such royalties. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 3 -- License Conditions. | ||||||
|  | 
 | ||||||
|  | Your exercise of the Licensed Rights is expressly made subject to the | ||||||
|  | following conditions. | ||||||
|  | 
 | ||||||
|  |   a. Attribution. | ||||||
|  | 
 | ||||||
|  |        1. If You Share the Licensed Material (including in modified | ||||||
|  |           form), You must: | ||||||
|  | 
 | ||||||
|  |             a. retain the following if it is supplied by the Licensor | ||||||
|  |                with the Licensed Material: | ||||||
|  | 
 | ||||||
|  |                  i. identification of the creator(s) of the Licensed | ||||||
|  |                     Material and any others designated to receive | ||||||
|  |                     attribution, in any reasonable manner requested by | ||||||
|  |                     the Licensor (including by pseudonym if | ||||||
|  |                     designated); | ||||||
|  | 
 | ||||||
|  |                 ii. a copyright notice; | ||||||
|  | 
 | ||||||
|  |                iii. a notice that refers to this Public License; | ||||||
|  | 
 | ||||||
|  |                 iv. a notice that refers to the disclaimer of | ||||||
|  |                     warranties; | ||||||
|  | 
 | ||||||
|  |                  v. a URI or hyperlink to the Licensed Material to the | ||||||
|  |                     extent reasonably practicable; | ||||||
|  | 
 | ||||||
|  |             b. indicate if You modified the Licensed Material and | ||||||
|  |                retain an indication of any previous modifications; and | ||||||
|  | 
 | ||||||
|  |             c. indicate the Licensed Material is licensed under this | ||||||
|  |                Public License, and include the text of, or the URI or | ||||||
|  |                hyperlink to, this Public License. | ||||||
|  | 
 | ||||||
|  |        2. You may satisfy the conditions in Section 3(a)(1) in any | ||||||
|  |           reasonable manner based on the medium, means, and context in | ||||||
|  |           which You Share the Licensed Material. For example, it may be | ||||||
|  |           reasonable to satisfy the conditions by providing a URI or | ||||||
|  |           hyperlink to a resource that includes the required | ||||||
|  |           information. | ||||||
|  | 
 | ||||||
|  |        3. If requested by the Licensor, You must remove any of the | ||||||
|  |           information required by Section 3(a)(1)(A) to the extent | ||||||
|  |           reasonably practicable. | ||||||
|  | 
 | ||||||
|  |   b. ShareAlike. | ||||||
|  | 
 | ||||||
|  |      In addition to the conditions in Section 3(a), if You Share | ||||||
|  |      Adapted Material You produce, the following conditions also apply. | ||||||
|  | 
 | ||||||
|  |        1. The Adapter's License You apply must be a Creative Commons | ||||||
|  |           license with the same License Elements, this version or | ||||||
|  |           later, or a BY-SA Compatible License. | ||||||
|  | 
 | ||||||
|  |        2. You must include the text of, or the URI or hyperlink to, the | ||||||
|  |           Adapter's License You apply. You may satisfy this condition | ||||||
|  |           in any reasonable manner based on the medium, means, and | ||||||
|  |           context in which You Share Adapted Material. | ||||||
|  | 
 | ||||||
|  |        3. You may not offer or impose any additional or different terms | ||||||
|  |           or conditions on, or apply any Effective Technological | ||||||
|  |           Measures to, Adapted Material that restrict exercise of the | ||||||
|  |           rights granted under the Adapter's License You apply. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 4 -- Sui Generis Database Rights. | ||||||
|  | 
 | ||||||
|  | Where the Licensed Rights include Sui Generis Database Rights that | ||||||
|  | apply to Your use of the Licensed Material: | ||||||
|  | 
 | ||||||
|  |   a. for the avoidance of doubt, Section 2(a)(1) grants You the right | ||||||
|  |      to extract, reuse, reproduce, and Share all or a substantial | ||||||
|  |      portion of the contents of the database; | ||||||
|  | 
 | ||||||
|  |   b. if You include all or a substantial portion of the database | ||||||
|  |      contents in a database in which You have Sui Generis Database | ||||||
|  |      Rights, then the database in which You have Sui Generis Database | ||||||
|  |      Rights (but not its individual contents) is Adapted Material, | ||||||
|  | 
 | ||||||
|  |      including for purposes of Section 3(b); and | ||||||
|  |   c. You must comply with the conditions in Section 3(a) if You Share | ||||||
|  |      all or a substantial portion of the contents of the database. | ||||||
|  | 
 | ||||||
|  | For the avoidance of doubt, this Section 4 supplements and does not | ||||||
|  | replace Your obligations under this Public License where the Licensed | ||||||
|  | Rights include other Copyright and Similar Rights. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 5 -- Disclaimer of Warranties and Limitation of Liability. | ||||||
|  | 
 | ||||||
|  |   a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE | ||||||
|  |      EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS | ||||||
|  |      AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF | ||||||
|  |      ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, | ||||||
|  |      IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, | ||||||
|  |      WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||||||
|  |      PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, | ||||||
|  |      ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT | ||||||
|  |      KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT | ||||||
|  |      ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. | ||||||
|  | 
 | ||||||
|  |   b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE | ||||||
|  |      TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, | ||||||
|  |      NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, | ||||||
|  |      INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, | ||||||
|  |      COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR | ||||||
|  |      USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN | ||||||
|  |      ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR | ||||||
|  |      DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR | ||||||
|  |      IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. | ||||||
|  | 
 | ||||||
|  |   c. The disclaimer of warranties and limitation of liability provided | ||||||
|  |      above shall be interpreted in a manner that, to the extent | ||||||
|  |      possible, most closely approximates an absolute disclaimer and | ||||||
|  |      waiver of all liability. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 6 -- Term and Termination. | ||||||
|  | 
 | ||||||
|  |   a. This Public License applies for the term of the Copyright and | ||||||
|  |      Similar Rights licensed here. However, if You fail to comply with | ||||||
|  |      this Public License, then Your rights under this Public License | ||||||
|  |      terminate automatically. | ||||||
|  | 
 | ||||||
|  |   b. Where Your right to use the Licensed Material has terminated under | ||||||
|  |      Section 6(a), it reinstates: | ||||||
|  | 
 | ||||||
|  |        1. automatically as of the date the violation is cured, provided | ||||||
|  |           it is cured within 30 days of Your discovery of the | ||||||
|  |           violation; or | ||||||
|  | 
 | ||||||
|  |        2. upon express reinstatement by the Licensor. | ||||||
|  | 
 | ||||||
|  |      For the avoidance of doubt, this Section 6(b) does not affect any | ||||||
|  |      right the Licensor may have to seek remedies for Your violations | ||||||
|  |      of this Public License. | ||||||
|  | 
 | ||||||
|  |   c. For the avoidance of doubt, the Licensor may also offer the | ||||||
|  |      Licensed Material under separate terms or conditions or stop | ||||||
|  |      distributing the Licensed Material at any time; however, doing so | ||||||
|  |      will not terminate this Public License. | ||||||
|  | 
 | ||||||
|  |   d. Sections 1, 5, 6, 7, and 8 survive termination of this Public | ||||||
|  |      License. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 7 -- Other Terms and Conditions. | ||||||
|  | 
 | ||||||
|  |   a. The Licensor shall not be bound by any additional or different | ||||||
|  |      terms or conditions communicated by You unless expressly agreed. | ||||||
|  | 
 | ||||||
|  |   b. Any arrangements, understandings, or agreements regarding the | ||||||
|  |      Licensed Material not stated herein are separate from and | ||||||
|  |      independent of the terms and conditions of this Public License. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Section 8 -- Interpretation. | ||||||
|  | 
 | ||||||
|  |   a. For the avoidance of doubt, this Public License does not, and | ||||||
|  |      shall not be interpreted to, reduce, limit, restrict, or impose | ||||||
|  |      conditions on any use of the Licensed Material that could lawfully | ||||||
|  |      be made without permission under this Public License. | ||||||
|  | 
 | ||||||
|  |   b. To the extent possible, if any provision of this Public License is | ||||||
|  |      deemed unenforceable, it shall be automatically reformed to the | ||||||
|  |      minimum extent necessary to make it enforceable. If the provision | ||||||
|  |      cannot be reformed, it shall be severed from this Public License | ||||||
|  |      without affecting the enforceability of the remaining terms and | ||||||
|  |      conditions. | ||||||
|  | 
 | ||||||
|  |   c. No term or condition of this Public License will be waived and no | ||||||
|  |      failure to comply consented to unless expressly agreed to by the | ||||||
|  |      Licensor. | ||||||
|  | 
 | ||||||
|  |   d. Nothing in this Public License constitutes or may be interpreted | ||||||
|  |      as a limitation upon, or waiver of, any privileges and immunities | ||||||
|  |      that apply to the Licensor or You, including from the legal | ||||||
|  |      processes of any jurisdiction or authority. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ======================================================================= | ||||||
|  | 
 | ||||||
|  | Creative Commons is not a party to its public | ||||||
|  | licenses. Notwithstanding, Creative Commons may elect to apply one of | ||||||
|  | its public licenses to material it publishes and in those instances | ||||||
|  | will be considered the “Licensor.” The text of the Creative Commons | ||||||
|  | public licenses is dedicated to the public domain under the CC0 Public | ||||||
|  | Domain Dedication. Except for the limited purpose of indicating that | ||||||
|  | material is shared under a Creative Commons public license or as | ||||||
|  | otherwise permitted by the Creative Commons policies published at | ||||||
|  | creativecommons.org/policies, Creative Commons does not authorize the | ||||||
|  | use of the trademark "Creative Commons" or any other trademark or logo | ||||||
|  | of Creative Commons without its prior written consent including, | ||||||
|  | without limitation, in connection with any unauthorized modifications | ||||||
|  | to any of its public licenses or any other arrangements, | ||||||
|  | understandings, or agreements concerning use of licensed material. For | ||||||
|  | the avoidance of doubt, this paragraph does not form part of the | ||||||
|  | public licenses. | ||||||
|  | 
 | ||||||
|  | Creative Commons may be contacted at creativecommons.org. | ||||||
							
								
								
									
										17
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,17 @@ | ||||||
|  | # Slice (SDDM Theme) | ||||||
|  | 
 | ||||||
|  | Simple dark SDDM theme. | ||||||
|  | 
 | ||||||
|  | ## Installing | ||||||
|  | 
 | ||||||
|  | 1. Install QML modules:  | ||||||
|  |   * Qt Graphical Effects | ||||||
|  |   * Qt Quick Controls | ||||||
|  | 2. Install Roboto font | ||||||
|  | 3. `git clone https://github.com/RadRussianRus/sddm-slice.git` | ||||||
|  | 4. `cp -r sddm-slice /usr/share/sddm/themes/sddm-slice` | ||||||
|  | 5. Open `/etc/sddm.conf` and put `Current=sddm-slice` in `[Theme]` section | ||||||
|  | 
 | ||||||
|  | ## License | ||||||
|  | 
 | ||||||
|  | [](http://creativecommons.org/licenses/by-sa/4.0/) | ||||||
							
								
								
									
										74
									
								
								slice/LoopListPowerItem.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,74 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 2.0 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: itemRoot | ||||||
|  |     opacity: distance | ||||||
|  |     property int duration: 100 | ||||||
|  | 
 | ||||||
|  |     signal clicked() | ||||||
|  |     signal entered() | ||||||
|  | 
 | ||||||
|  |     transform: Scale | ||||||
|  |     { | ||||||
|  |         origin.x: 54 | ||||||
|  |         origin.y: 29 | ||||||
|  |         xScale: distance | ||||||
|  |         yScale: distance | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Behavior on distance | ||||||
|  |     { | ||||||
|  |         PropertyAnimation { duration: itemRoot.duration } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     property real distance: 1.0 | ||||||
|  |     property string icon: "icons/no_avatar.svg" | ||||||
|  |     property string title: "" | ||||||
|  | 
 | ||||||
|  |     Image | ||||||
|  |     { | ||||||
|  |         id: powerItemIcon | ||||||
|  |         source: icon | ||||||
|  |         sourceSize.width: 48 | ||||||
|  |         sourceSize.height: 48 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ColorOverlay | ||||||
|  |     { | ||||||
|  |         id: powerItemIconOverlay | ||||||
|  |         anchors.fill: powerItemIcon | ||||||
|  |         source: powerItemIcon | ||||||
|  |         color: "#dddddd" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Label | ||||||
|  |     { | ||||||
|  |         id: descriptionLabel | ||||||
|  |         text: itemRoot.title | ||||||
|  |         color: "#fff" | ||||||
|  | 
 | ||||||
|  |         font | ||||||
|  |         { | ||||||
|  |             family: "Roboto" | ||||||
|  |             pointSize: 28 | ||||||
|  |             bold: true | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         x: 54 | ||||||
|  |         y: 5 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MouseArea | ||||||
|  |     { | ||||||
|  |         width: descriptionLabel.x + descriptionLabel.width | ||||||
|  |         height: 48 | ||||||
|  |         hoverEnabled: true | ||||||
|  | 
 | ||||||
|  |         onClicked: itemRoot.clicked() | ||||||
|  |         onEntered: itemRoot.entered() | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								slice/LoopListSessionItem.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,32 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 2.0 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: itemRoot | ||||||
|  |     opacity: distance | ||||||
|  |     scale: distance | ||||||
|  | 
 | ||||||
|  |     property real distance: 1.0 | ||||||
|  |     property string sessionName: "" | ||||||
|  | 
 | ||||||
|  |     Label | ||||||
|  |     { | ||||||
|  |         id: sessionNameLabel | ||||||
|  |         anchors.centerIn: parent | ||||||
|  |         text: sessionName | ||||||
|  |         color: "#fff" | ||||||
|  | 
 | ||||||
|  |         font | ||||||
|  |         { | ||||||
|  |             family: "Roboto" | ||||||
|  |             pointSize: 28 | ||||||
|  |             bold: true | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         x: parent.x | ||||||
|  |         y: 0 | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								slice/LoopListUserItem.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,68 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 2.0 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: itemRoot | ||||||
|  |     opacity: distance | ||||||
|  | 
 | ||||||
|  |     transform: Scale | ||||||
|  |     { | ||||||
|  |         origin.x: 80 | ||||||
|  |         xScale: distance | ||||||
|  |         yScale: distance | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     property real distance: 1.0 | ||||||
|  |     property string userName: "" | ||||||
|  |     property string userLogin: "" | ||||||
|  |     property string userAvatar: "icons/no_avatar.svg" | ||||||
|  | 
 | ||||||
|  |     Image | ||||||
|  |     { | ||||||
|  |         id: profilePicture | ||||||
|  |         source: userAvatar | ||||||
|  |         sourceSize.width: 64 | ||||||
|  |         sourceSize.height: 64 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ColorOverlay | ||||||
|  |     { | ||||||
|  |         id: profilePictureOverlay | ||||||
|  |         anchors.fill: profilePicture | ||||||
|  |         source: profilePicture | ||||||
|  |         color: "#dddddd" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Label | ||||||
|  |     { | ||||||
|  |         text: userName | ||||||
|  |         color: "#fff" | ||||||
|  |          | ||||||
|  |         font | ||||||
|  |         { | ||||||
|  |             family: "Roboto" | ||||||
|  |             pointSize: 28 | ||||||
|  |             bold: true | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         x: 80 | ||||||
|  |         y: 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Label | ||||||
|  |     { | ||||||
|  |         text: userLogin | ||||||
|  |         color: "#fff" | ||||||
|  |         y: userName == "" ? 5 : 36 | ||||||
|  |         font | ||||||
|  |         { | ||||||
|  |             family: "Roboto" | ||||||
|  |             pointSize: userName == "" ? 36 : 20 | ||||||
|  |             bold: userName == "" | ||||||
|  |         } | ||||||
|  |         x: 80 | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										276
									
								
								slice/Main.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,276 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 1.4 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Rectangle | ||||||
|  | { | ||||||
|  |     id: root | ||||||
|  |     color: "#222222" | ||||||
|  | 
 | ||||||
|  |     state: "stateUsers" | ||||||
|  |     states: | ||||||
|  |     [ | ||||||
|  |         State | ||||||
|  |         { | ||||||
|  |             name: "statePower" | ||||||
|  |              | ||||||
|  |             PropertyChanges { target: pagePower;    enabled: true ; focus: true ; x: 0 } | ||||||
|  |             PropertyChanges { target: pageSessions; enabled: false; focus: false; x: areaMain.width } | ||||||
|  |             PropertyChanges { target: pageUsers;    enabled: false; focus: false; x: areaMain.width * 2 } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges { target: buttonPagePower;    selected: true  } | ||||||
|  |             PropertyChanges { target: buttonPageSessions; selected: false } | ||||||
|  |             PropertyChanges { target: buttonPageUsers;    selected: false } | ||||||
|  | 
 | ||||||
|  |         }, | ||||||
|  |         State | ||||||
|  |         { | ||||||
|  |             name: "stateSessions" | ||||||
|  | 
 | ||||||
|  |             PropertyChanges { target: pagePower;    enabled: false; focus: false; x: -areaMain.width } | ||||||
|  |             PropertyChanges { target: pageSessions; enabled: true ; focus: true ; x: 0 } | ||||||
|  |             PropertyChanges { target: pageUsers;    enabled: false; focus: false; x: areaMain.width } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges { target: buttonPagePower;    selected: false } | ||||||
|  |             PropertyChanges { target: buttonPageSessions; selected: true  } | ||||||
|  |             PropertyChanges { target: buttonPageUsers;    selected: false } | ||||||
|  |         }, | ||||||
|  |         State | ||||||
|  |         { | ||||||
|  |             name: "stateUsers" | ||||||
|  | 
 | ||||||
|  |             PropertyChanges { target: pagePower;    enabled: false; focus: false; x: -areaMain.width * 2 } | ||||||
|  |             PropertyChanges { target: pageSessions; enabled: false; focus: false; x: -areaMain.width } | ||||||
|  |             PropertyChanges { target: pageUsers;    enabled: true ; focus: true ; x: 0 } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges { target: buttonPagePower;    selected: false } | ||||||
|  |             PropertyChanges { target: buttonPageSessions; selected: false } | ||||||
|  |             PropertyChanges { target: buttonPageUsers;    selected: true  } | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     TextConstants { id: localeText } | ||||||
|  | 
 | ||||||
|  |     Item | ||||||
|  |     { | ||||||
|  |         id: areaTop | ||||||
|  |         x: 0 | ||||||
|  |         y: 0 | ||||||
|  |         width: root.width | ||||||
|  |         height: 35 | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonPagePower | ||||||
|  |             x: 5 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             hasLeftSlice: false | ||||||
|  |             text: sddm.hostName ? sddm.hostName : "Hostname" | ||||||
|  | 
 | ||||||
|  |             enabled: sddm.canPowerOff || sddm.canReboot || sddm.canSuspend || sddm.canHibernate || sddm.canHybridSleep | ||||||
|  | 
 | ||||||
|  |             onClicked: if (enabled) root.state = "statePower" | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonPageSessions | ||||||
|  |             x: buttonPagePower.x + buttonPagePower.widthPartial + 3 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             text: pageSessions.currentSessionName | ||||||
|  | 
 | ||||||
|  |             onClicked: root.state = "stateSessions" | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonPageUsers | ||||||
|  |             x: buttonPageSessions.x + buttonPageSessions.widthPartial + 3 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             text: pageUsers.currentUserLogin | ||||||
|  | 
 | ||||||
|  |             onClicked: root.state = "stateUsers" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Item | ||||||
|  |     { | ||||||
|  |         id: areaMain | ||||||
|  |         x: 0 | ||||||
|  |         y: areaTop.height | ||||||
|  |         width: root.width | ||||||
|  |         height: root.height - (areaTop.height * 2) | ||||||
|  | 
 | ||||||
|  |         PagePower | ||||||
|  |         { | ||||||
|  |             id: pagePower | ||||||
|  |             width: areaMain.width | ||||||
|  |             height: areaMain.height | ||||||
|  | 
 | ||||||
|  |             Keys.onTabPressed: { root.state = "stateSessions" } | ||||||
|  |             Keys.onBacktabPressed: { root.state = "stateUsers" } | ||||||
|  | 
 | ||||||
|  |             Behavior on x { NumberAnimation { duration: 150 } } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         PageSessions | ||||||
|  |         { | ||||||
|  |             id: pageSessions | ||||||
|  |             width: areaMain.width | ||||||
|  |             height: areaMain.height | ||||||
|  | 
 | ||||||
|  |             Keys.onTabPressed: { root.state = "stateUsers" } | ||||||
|  |             Keys.onBacktabPressed: | ||||||
|  |             { | ||||||
|  |                 if (buttonPagePower.enabled) | ||||||
|  |                     root.state = "statePower" | ||||||
|  |                 else | ||||||
|  |                     root.state = "stateSessions" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Behavior on x { NumberAnimation { duration: 150 } } | ||||||
|  | 
 | ||||||
|  |             onSelectedIndexChanged: pageUsers.selectedSessionIndex = selectedIndex | ||||||
|  | 
 | ||||||
|  |             onSessionSelected: root.state = "stateUsers" | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         PageUsers | ||||||
|  |         { | ||||||
|  |             id: pageUsers | ||||||
|  |             width: areaMain.width | ||||||
|  |             height: areaMain.height | ||||||
|  | 
 | ||||||
|  |             Keys.onTabPressed: | ||||||
|  |             { | ||||||
|  |                 if (buttonPagePower.enabled) | ||||||
|  |                     root.state = "statePower" | ||||||
|  |                 else | ||||||
|  |                     root.state = "stateSessions" | ||||||
|  |             } | ||||||
|  |             Keys.onBacktabPressed: { root.state = "stateSessions" } | ||||||
|  | 
 | ||||||
|  |             Behavior on x { NumberAnimation { duration: 150 } } | ||||||
|  | 
 | ||||||
|  |             onLockNav: areaTop.enabled = false | ||||||
|  |             onUnlockNav: areaTop.enabled = true | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Item | ||||||
|  |     { | ||||||
|  |         id: areaBottom | ||||||
|  |         x: 0 | ||||||
|  |         y: areaTop.height + areaMain.height | ||||||
|  |         width: root.width | ||||||
|  |         height: 35 | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonCapsLock | ||||||
|  |             x: 5 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             hasLeftSlice: false | ||||||
|  |             text: "Caps Lock" | ||||||
|  |             selected: keyboard.capsLock | ||||||
|  | 
 | ||||||
|  |             onClicked: keyboard.capsLock = !keyboard.capsLock | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonNumLock | ||||||
|  |             x: buttonCapsLock.x + buttonCapsLock.widthPartial + 3 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             text: "Num Lock" | ||||||
|  |             selected: keyboard.numLock | ||||||
|  | 
 | ||||||
|  |             onClicked: keyboard.numLock = !keyboard.numLock | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonKeyboardLayout | ||||||
|  |             x: buttonNumLock.x + buttonNumLock.widthPartial + 3 | ||||||
|  |             y: 5 | ||||||
|  | 
 | ||||||
|  |             text: keyboard.layouts[keyboard.currentLayout].longName | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Item | ||||||
|  |         { | ||||||
|  |             id: dateTimeArea | ||||||
|  |             x: areaBottom.width - width | ||||||
|  |             width: buttonWeekday.widthPartial + buttonDate.widthPartial + buttonTime.widthPartial + 21 | ||||||
|  | 
 | ||||||
|  |             SlicedButton | ||||||
|  |             { | ||||||
|  |                 id: buttonWeekday | ||||||
|  |                 x: 5 | ||||||
|  |                 y: 5 | ||||||
|  | 
 | ||||||
|  |                 function updateTime() | ||||||
|  |                 { | ||||||
|  |                     text = new Date().toLocaleString(Qt.locale(), | ||||||
|  |                         "dddd") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             SlicedButton | ||||||
|  |             { | ||||||
|  |                 id: buttonDate | ||||||
|  |                 x: buttonWeekday.x + buttonWeekday.widthPartial + 3 | ||||||
|  |                 y: 5 | ||||||
|  | 
 | ||||||
|  |                 function updateTime() | ||||||
|  |                 { | ||||||
|  |                     text = new Date().toLocaleString(Qt.locale(), | ||||||
|  |                         "dd.MM.yyyy") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             SlicedButton | ||||||
|  |             { | ||||||
|  |                 id: buttonTime | ||||||
|  |                 x: buttonDate.x + buttonDate.widthPartial + 3 | ||||||
|  |                 y: 5 | ||||||
|  | 
 | ||||||
|  |                 hasRightSlice: false | ||||||
|  | 
 | ||||||
|  |                 function updateTime() | ||||||
|  |                 { | ||||||
|  |                     text = new Date().toLocaleString(Qt.locale(), | ||||||
|  |                         "hh:mm:ss") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Timer | ||||||
|  |         { | ||||||
|  |             interval: 1000 | ||||||
|  |             repeat: true | ||||||
|  |             running: true | ||||||
|  |             onTriggered: | ||||||
|  |             { | ||||||
|  |                 buttonTime.updateTime() | ||||||
|  |                 buttonDate.updateTime() | ||||||
|  |                 buttonWeekday.updateTime() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Component.onCompleted: | ||||||
|  |         { | ||||||
|  |             buttonTime.updateTime() | ||||||
|  |             buttonDate.updateTime() | ||||||
|  |             buttonWeekday.updateTime() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										262
									
								
								slice/PagePower.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,262 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 2.0 | ||||||
|  | import QtQuick.Layouts 1.3 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: pageRoot | ||||||
|  | 
 | ||||||
|  |     property int selectedIndex: | ||||||
|  |     { | ||||||
|  |         if (sddm.canPowerOff) return 0 | ||||||
|  |         else if (sddm.canReboot) return 1 | ||||||
|  |         else if (sddm.canSuspend) return 2 | ||||||
|  |         else if (sddm.canHibernate) return 3 | ||||||
|  |         else if (sddm.canHybridSleep) return 4 | ||||||
|  |         else return 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function execute() | ||||||
|  |     { | ||||||
|  |         switch (selectedIndex) | ||||||
|  |         { | ||||||
|  |             case 0: | ||||||
|  |                 sddm.powerOff(); | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 1: | ||||||
|  |                 sddm.reboot(); | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 2: | ||||||
|  |                 sddm.suspend(); | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 3: | ||||||
|  |                 sddm.hibernate(); | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             case 4: | ||||||
|  |                 sddm.hybridSleep(); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     ColumnLayout | ||||||
|  |     { | ||||||
|  |         id: powerListContainer | ||||||
|  |         anchors.horizontalCenter: parent.horizontalCenter | ||||||
|  |         width: 350 | ||||||
|  |         height: pageRoot.height | ||||||
|  | 
 | ||||||
|  |         property int scrollDuration: 100 | ||||||
|  | 
 | ||||||
|  |         LoopListPowerItem | ||||||
|  |         { | ||||||
|  |             id: powerShutdownButton | ||||||
|  |             //y: pageRoot.height / 10 | ||||||
|  |             title: localeText.shutdown | ||||||
|  |             distance: selectedIndex == 0 ? 1.0 : 0.6 | ||||||
|  |             icon: "icons/power-off.svg" | ||||||
|  | 
 | ||||||
|  |             //Layout.fillHeight: true | ||||||
|  |             Layout.alignment: Qt.AlignVCenter | ||||||
|  |             Layout.minimumHeight: 48 | ||||||
|  | 
 | ||||||
|  |             visible: sddm.canPowerOff | ||||||
|  |             onEntered: selectedIndex = 0 | ||||||
|  |             onClicked: { selectedIndex = 0; execute() } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListPowerItem | ||||||
|  |         { | ||||||
|  |             id: powerRebootButton | ||||||
|  |             //y: pageRoot.height / 3.7 | ||||||
|  |             title: localeText.reboot | ||||||
|  |             distance: selectedIndex == 1 ? 1.0 : 0.6 | ||||||
|  |             icon: "icons/reboot.svg" | ||||||
|  | 
 | ||||||
|  |             //Layout.fillHeight: true | ||||||
|  |             Layout.alignment: Qt.AlignVCenter | ||||||
|  |             Layout.minimumHeight: 48 | ||||||
|  | 
 | ||||||
|  |             visible: sddm.canReboot | ||||||
|  | 
 | ||||||
|  |             onEntered: selectedIndex = 1 | ||||||
|  |             onClicked: { selectedIndex = 1; execute() } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListPowerItem | ||||||
|  |         { | ||||||
|  |             id: powerSuspendButton | ||||||
|  |             //y: pageRoot.height / 2.2 | ||||||
|  |             title: qsTr("Suspend") | ||||||
|  |             distance: selectedIndex == 2 ? 1.0 : 0.6 | ||||||
|  |             icon: "icons/suspend.svg" | ||||||
|  | 
 | ||||||
|  |             //Layout.fillHeight: true | ||||||
|  |             Layout.alignment: Qt.AlignVCenter | ||||||
|  |             Layout.minimumHeight: 48 | ||||||
|  | 
 | ||||||
|  |             visible: sddm.canSuspend | ||||||
|  | 
 | ||||||
|  |             onEntered: selectedIndex = 2 | ||||||
|  |             onClicked: { selectedIndex = 2; execute() } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListPowerItem | ||||||
|  |         { | ||||||
|  |             id: powerHibernateButton | ||||||
|  |             //y: pageRoot.height / 1.58 | ||||||
|  |             title: qsTr("Hibernate") | ||||||
|  |             distance: selectedIndex == 3 ? 1.0 : 0.6 | ||||||
|  |             icon: "icons/hibernate.svg" | ||||||
|  | 
 | ||||||
|  |             //Layout.fillHeight: true | ||||||
|  |             Layout.alignment: Qt.AlignVCenter | ||||||
|  |             Layout.minimumHeight: 48 | ||||||
|  | 
 | ||||||
|  |             visible: sddm.canHibernate | ||||||
|  | 
 | ||||||
|  |             onEntered: selectedIndex = 3 | ||||||
|  |             onClicked: { selectedIndex = 3; execute() } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListPowerItem | ||||||
|  |         { | ||||||
|  |             id: powerHybridSleepButton | ||||||
|  |             //y: pageRoot.height / 1.25 | ||||||
|  |             title: qsTr("Hybrid Sleep") | ||||||
|  |             distance: selectedIndex == 4 ? 1.0 : 0.6 | ||||||
|  |             icon: "icons/hybrid-sleep.svg" | ||||||
|  | 
 | ||||||
|  |             //Layout.fillHeight: true | ||||||
|  |             Layout.alignment: Qt.AlignVCenter | ||||||
|  |             Layout.minimumHeight: 48 | ||||||
|  | 
 | ||||||
|  |             visible: sddm.canHybridSleep | ||||||
|  | 
 | ||||||
|  |             onEntered: selectedIndex = 4 | ||||||
|  |             onClicked: { selectedIndex = 4; execute() } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_up() | ||||||
|  |     { | ||||||
|  |         selectedIndex = next_index(selectedIndex) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_down() | ||||||
|  |     { | ||||||
|  |         selectedIndex = prev_index(selectedIndex) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function next_index(index) | ||||||
|  |     { | ||||||
|  |         var result = index | ||||||
|  |         var actionFound = false | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         while (!actionFound) | ||||||
|  |         { | ||||||
|  |             if (result >= 4) | ||||||
|  |                 result = 0 | ||||||
|  |             else | ||||||
|  |                 result++ | ||||||
|  | 
 | ||||||
|  |             if (result == index) break | ||||||
|  | 
 | ||||||
|  |             switch (result) | ||||||
|  |             { | ||||||
|  |                 case 0: | ||||||
|  |                     if (sddm.canPowerOff) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 1: | ||||||
|  |                     if (sddm.canReboot) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 2: | ||||||
|  |                     if (sddm.canSuspend) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 3: | ||||||
|  |                     if (sddm.canHibernate) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 4: | ||||||
|  |                     if (sddm.canHybridSleep) actionFound = true | ||||||
|  |                     break | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function prev_index(index) | ||||||
|  |     { | ||||||
|  |         var result = index | ||||||
|  |         var actionFound = false | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         while (!actionFound) | ||||||
|  |         { | ||||||
|  |             if (result <= 0) | ||||||
|  |                 result = 4 | ||||||
|  |             else | ||||||
|  |                 result-- | ||||||
|  | 
 | ||||||
|  |             if (result == index) break | ||||||
|  | 
 | ||||||
|  |             switch (result) | ||||||
|  |             { | ||||||
|  |                 case 0: | ||||||
|  |                     if (sddm.canPowerOff) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 1: | ||||||
|  |                     if (sddm.canReboot) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 2: | ||||||
|  |                     if (sddm.canSuspend) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 3: | ||||||
|  |                     if (sddm.canHibernate) actionFound = true | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
|  |                 case 4: | ||||||
|  |                     if (sddm.canHybridSleep) actionFound = true | ||||||
|  |                     break | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Keys.onUpPressed: scroll_down() | ||||||
|  |     Keys.onDownPressed: scroll_up() | ||||||
|  |     Keys.onEnterPressed: execute() | ||||||
|  |     Keys.onReturnPressed: execute() | ||||||
|  | 
 | ||||||
|  |     MouseArea | ||||||
|  |     { | ||||||
|  |         id: listMouseArea | ||||||
|  |         anchors.fill: parent | ||||||
|  |         propagateComposedEvents: true | ||||||
|  |         onWheel: | ||||||
|  |         { | ||||||
|  |             if (wheel.pixelDelta.y < 0) | ||||||
|  |                 scroll_up() | ||||||
|  |             else | ||||||
|  |                 scroll_down() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										297
									
								
								slice/PageSessions.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,297 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 2.0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: pageRoot | ||||||
|  | 
 | ||||||
|  |     property int selectedIndex: sessionModel.lastIndex | ||||||
|  |     property string currentSessionName: get_name(0) | ||||||
|  |     property int scrollRepeat: 0 | ||||||
|  | 
 | ||||||
|  |     function get_relative_index(relate) | ||||||
|  |     { | ||||||
|  |         var count = sessionModel.rowCount() | ||||||
|  |         if (count <= 0) | ||||||
|  |             return 0 | ||||||
|  | 
 | ||||||
|  |         var index = selectedIndex + relate | ||||||
|  | 
 | ||||||
|  |         if (index < 0) | ||||||
|  |             while (index < 0) | ||||||
|  |                 index = count + index | ||||||
|  |         else if (index >= count) | ||||||
|  |             while (index >= count) | ||||||
|  |                 index = index - count | ||||||
|  | 
 | ||||||
|  |         return index | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function get_name(relate) | ||||||
|  |     { | ||||||
|  |         // Qt.UserRole + 4 is SDDM.NameRole (from src/greeter/SessionModel.h) | ||||||
|  |         return sessionModel.data(sessionModel.index(get_relative_index(relate), 0), Qt.UserRole + 4) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     signal sessionSelected() | ||||||
|  | 
 | ||||||
|  |     Item | ||||||
|  |     { | ||||||
|  |         id: sessionListContainer | ||||||
|  |         anchors.horizontalCenter: parent.horizontalCenter | ||||||
|  | 
 | ||||||
|  |         property int scrollDuration: 100 | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: topFarItemMouseArea | ||||||
|  |             hoverEnabled: true | ||||||
|  |             x: -225 | ||||||
|  |             width: 450 | ||||||
|  |             height: pageRoot.height / 6 | ||||||
|  | 
 | ||||||
|  |             onClicked: { scrollRepeat = 1; scroll_down(); } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: topMidItemMouseArea | ||||||
|  |             y: topFarItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             x: -225 | ||||||
|  |             width: 450 | ||||||
|  |             height: pageRoot.height / 5 | ||||||
|  | 
 | ||||||
|  |             onClicked: scroll_down() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: middleItemMouseArea | ||||||
|  |             y: topMidItemMouseArea.y + topMidItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             x: -225 | ||||||
|  |             width: 450 | ||||||
|  |             height: pageRoot.height / 4 | ||||||
|  | 
 | ||||||
|  |             onClicked: pageRoot.sessionSelected() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: botMidItemMouseArea | ||||||
|  |             y: middleItemMouseArea.y + middleItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             x: -225 | ||||||
|  |             width: 450 | ||||||
|  |             height: pageRoot.height / 5 | ||||||
|  | 
 | ||||||
|  |             onClicked: scroll_up() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: botFarItemMouseArea | ||||||
|  |             y: botMidItemMouseArea.y + botMidItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             x: -225 | ||||||
|  |             width: 450 | ||||||
|  |             height: pageRoot.height / 6 | ||||||
|  | 
 | ||||||
|  |             onClicked: { scrollRepeat = 1; scroll_up(); } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: topFallbackItem | ||||||
|  |             y: 0 | ||||||
|  |             distance: 0 | ||||||
|  |             sessionName: get_name(-3) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: topFarItem | ||||||
|  |             y: pageRoot.height / 18 | ||||||
|  |             distance: 0.33 | ||||||
|  |             sessionName: get_name(-2) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: topMidItem | ||||||
|  |             y: pageRoot.height / 4.3 | ||||||
|  |             distance: 0.66 | ||||||
|  |             sessionName: get_name(-1) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: middleItem | ||||||
|  |             y: pageRoot.height / 2.1 | ||||||
|  |             sessionName: get_name(0) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: botMidItem | ||||||
|  |             y: pageRoot.height / 1.4 | ||||||
|  |             distance: 0.66 | ||||||
|  |             sessionName: get_name(1) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: botFarItem | ||||||
|  |             y: pageRoot.height / 1.1 | ||||||
|  |             distance: 0.33 | ||||||
|  |             sessionName: get_name(2) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListSessionItem | ||||||
|  |         { | ||||||
|  |             id: botFallbackItem | ||||||
|  |             y: pageRoot.height | ||||||
|  |             distance: 0 | ||||||
|  |             sessionName: get_name(3) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: sessionListScrollUp | ||||||
|  |             NumberAnimation { target: topFarItem; property: "y"; to: 0; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0; duration: sessionListContainer.scrollDuration } | ||||||
|  |              | ||||||
|  |             NumberAnimation { target: topMidItem; property: "y"; to: pageRoot.height / 18; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 0.33; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 4.3; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "distance"; to: 0.66; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botMidItem; property: "y"; to: pageRoot.height / 2.1; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 1; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFarItem; property: "y"; to: pageRoot.height / 1.4; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0.66; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFallbackItem; property: "y"; to: pageRoot.height / 1.1; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFallbackItem; property: "distance"; to: 0.33; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 if (selectedIndex >= sessionModel.rowCount() - 1) | ||||||
|  |                     selectedIndex = 0 | ||||||
|  |                 else | ||||||
|  |                     selectedIndex++ | ||||||
|  | 
 | ||||||
|  |                 reset_items() | ||||||
|  | 
 | ||||||
|  |                 if (scrollRepeat > 0) | ||||||
|  |                 { | ||||||
|  |                     scrollRepeat-- | ||||||
|  |                     sessionListScrollUp.start() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: sessionListScrollDown | ||||||
|  |             NumberAnimation { target: topFallbackItem; property: "y"; to: pageRoot.height / 18; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFallbackItem; property: "distance"; to: 0.33; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: topFarItem; property: "y"; to: pageRoot.height / 4.3; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0.66; duration: sessionListContainer.scrollDuration } | ||||||
|  |              | ||||||
|  |             NumberAnimation { target: topMidItem; property: "y"; to: pageRoot.height / 2.1; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 1; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 1.4; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "distance"; to: 0.66; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botMidItem; property: "y"; to: pageRoot.height / 1.1; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 0.33; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFarItem; property: "y"; to: pageRoot.height; duration: sessionListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0; duration: sessionListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 if (selectedIndex <= 0) | ||||||
|  |                     selectedIndex = sessionModel.rowCount() - 1 | ||||||
|  |                 else | ||||||
|  |                     selectedIndex-- | ||||||
|  |                  | ||||||
|  |                 reset_items() | ||||||
|  | 
 | ||||||
|  |                 if (scrollRepeat > 0) | ||||||
|  |                 { | ||||||
|  |                     scrollRepeat-- | ||||||
|  |                     sessionListScrollDown.start() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function reset_items() | ||||||
|  |     { | ||||||
|  |         topFallbackItem.y = 0 | ||||||
|  |         topFallbackItem.distance = 0 | ||||||
|  | 
 | ||||||
|  |         topFarItem.y = pageRoot.height / 18 | ||||||
|  |         topFarItem.distance = 0.33 | ||||||
|  | 
 | ||||||
|  |         topMidItem.y = pageRoot.height / 4.3 | ||||||
|  |         topMidItem.distance = 0.66 | ||||||
|  | 
 | ||||||
|  |         middleItem.y = pageRoot.height / 2.1 | ||||||
|  |         middleItem.distance = 1 | ||||||
|  | 
 | ||||||
|  |         botMidItem.y = pageRoot.height / 1.4 | ||||||
|  |         botMidItem.distance = 0.66 | ||||||
|  | 
 | ||||||
|  |         botFarItem.y = pageRoot.height / 1.1 | ||||||
|  |         botFarItem.distance = 0.33 | ||||||
|  | 
 | ||||||
|  |         botFallbackItem.y = pageRoot.height | ||||||
|  |         botFallbackItem.distance = 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_up() | ||||||
|  |     { | ||||||
|  |         sessionListScrollUp.start() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_down() | ||||||
|  |     { | ||||||
|  |         sessionListScrollDown.start() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Keys.onUpPressed: scroll_down() | ||||||
|  |     Keys.onDownPressed: scroll_up() | ||||||
|  |     Keys.onEnterPressed: pageRoot.sessionSelected() | ||||||
|  |     Keys.onReturnPressed: pageRoot.sessionSelected() | ||||||
|  | 
 | ||||||
|  |     MouseArea | ||||||
|  |     { | ||||||
|  |         id: listMouseArea | ||||||
|  |         anchors.fill: parent | ||||||
|  |         propagateComposedEvents: true | ||||||
|  |         onWheel: | ||||||
|  |         { | ||||||
|  |             if (wheel.pixelDelta.y < 0) | ||||||
|  |                 scroll_up() | ||||||
|  |             else | ||||||
|  |                 scroll_down() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										608
									
								
								slice/PageUsers.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,608 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtGraphicalEffects 1.0 | ||||||
|  | import SddmComponents 2.0 | ||||||
|  | import QtQuick.Controls 1.4 | ||||||
|  | import QtQuick.Controls.Styles 1.4 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: pageRoot | ||||||
|  |     focus: true | ||||||
|  | 
 | ||||||
|  |     property int selectedIndex: userModel.lastIndex | ||||||
|  |     property int selectedSessionIndex: sessionModel.lastIndex | ||||||
|  |     property int scrollRepeat: 0 | ||||||
|  |     property string currentUserLogin: get_login(0) | ||||||
|  |     property bool hasLoginShown: true | ||||||
|  | 
 | ||||||
|  |     signal lockNav() | ||||||
|  |     signal unlockNav() | ||||||
|  | 
 | ||||||
|  |     function get_relative_index(relate) | ||||||
|  |     { | ||||||
|  |         var count = userModel.count | ||||||
|  |         if (count <= 0) | ||||||
|  |             return 0 | ||||||
|  | 
 | ||||||
|  |         var index = selectedIndex + relate | ||||||
|  | 
 | ||||||
|  |         if (index < 0) | ||||||
|  |             while (index < 0) | ||||||
|  |                 index = count + index | ||||||
|  |         else if (index >= count) | ||||||
|  |             while (index >= count) | ||||||
|  |                 index = index - count | ||||||
|  | 
 | ||||||
|  |         return index | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function get_login(relate) | ||||||
|  |     { | ||||||
|  |         // Qt.UserRole + 1 is SDDM.NameRole (from src/greeter/UserModel.h) | ||||||
|  |         return userModel.data(userModel.index(get_relative_index(relate), 0), Qt.UserRole + 1) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function get_name(relate) | ||||||
|  |     { | ||||||
|  |         // Qt.UserRole + 2 is SDDM.RealNameRole (from src/greeter/UserModel.h) | ||||||
|  |         return userModel.data(userModel.index(get_relative_index(relate), 0), Qt.UserRole + 2) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function get_avatar(relate) | ||||||
|  |     { | ||||||
|  |         // Qt.UserRole + 4 is SDDM.IconRole (from src/greeter/UserModel.h) | ||||||
|  |         return userModel.data(userModel.index(get_relative_index(relate), 0), Qt.UserRole + 4) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Connections | ||||||
|  |     { | ||||||
|  |         target: sddm | ||||||
|  | 
 | ||||||
|  |         onLoginFailed: | ||||||
|  |         { | ||||||
|  |             errorMessage.opacity = 1 | ||||||
|  |             pageRoot.enabled = true | ||||||
|  |             pageRoot.unlockNav() | ||||||
|  |             loginExitAnimation.start() | ||||||
|  |             passwordField.text = "" | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onFocusChanged: | ||||||
|  |     { | ||||||
|  |         if (focus && hasLoginShown) | ||||||
|  |             passwordField.forceActiveFocus() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Item | ||||||
|  |     { | ||||||
|  |         id: userListContainer | ||||||
|  |         anchors.horizontalCenter: parent.horizontalCenter | ||||||
|  |         width: 450 | ||||||
|  | 
 | ||||||
|  |         property int scrollDuration: 100 | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: topFarItemMouseArea | ||||||
|  |             hoverEnabled: true | ||||||
|  |             width: parent.width | ||||||
|  |             height: pageRoot.height / 6 | ||||||
|  |             enabled: !hasLoginShown | ||||||
|  | 
 | ||||||
|  |             onClicked: { scrollRepeat = 1; scroll_down(); } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: topMidItemMouseArea | ||||||
|  |             y: topFarItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             width: parent.width | ||||||
|  |             height: pageRoot.height / 5 | ||||||
|  |             enabled: !hasLoginShown | ||||||
|  | 
 | ||||||
|  |             onClicked: scroll_down() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: middleItemMouseArea | ||||||
|  |             y: topMidItemMouseArea.y + topMidItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             width: parent.width | ||||||
|  |             height: pageRoot.height / 4 | ||||||
|  |             enabled: !hasLoginShown | ||||||
|  | 
 | ||||||
|  |             onClicked: select_or_login() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: botMidItemMouseArea | ||||||
|  |             y: middleItemMouseArea.y + middleItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             width: parent.width | ||||||
|  |             height: pageRoot.height / 5 | ||||||
|  |             enabled: !hasLoginShown | ||||||
|  | 
 | ||||||
|  |             onClicked: scroll_up() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MouseArea | ||||||
|  |         { | ||||||
|  |             id: botFarItemMouseArea | ||||||
|  |             y: botMidItemMouseArea.y + botMidItemMouseArea.height | ||||||
|  |             hoverEnabled: true | ||||||
|  |             width: parent.width | ||||||
|  |             height: pageRoot.height / 6 | ||||||
|  |             enabled: !hasLoginShown | ||||||
|  | 
 | ||||||
|  |             onClicked: { scrollRepeat = 1; scroll_up(); } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: topFallbackItem | ||||||
|  |             y: 0 | ||||||
|  |             distance: 0 | ||||||
|  |             userName: get_name(-3) | ||||||
|  |             userLogin: get_login(-3) | ||||||
|  |             userAvatar: get_avatar(-3) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: topFarItem | ||||||
|  |             y: pageRoot.height / 18 | ||||||
|  |             distance: hasLoginShown ? 0 : 0.4 | ||||||
|  |             userName: get_name(-2) | ||||||
|  |             userLogin: get_login(-2) | ||||||
|  |             userAvatar: get_avatar(-2) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: topMidItem | ||||||
|  |             y: pageRoot.height / 4.7 | ||||||
|  |             distance: hasLoginShown ? 0 : 0.7 | ||||||
|  |             userName: get_name(-1) | ||||||
|  |             userLogin: get_login(-1) | ||||||
|  |             userAvatar: get_avatar(-1) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: middleItem | ||||||
|  |             y: hasLoginShown ? pageRoot.height / 2.3 - 40 : pageRoot.height / 2.3 | ||||||
|  |             userName: get_name(0) | ||||||
|  |             userLogin: get_login(0) | ||||||
|  |             userAvatar: get_avatar(0) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |          | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: botMidItem | ||||||
|  |             y: pageRoot.height / 1.45 | ||||||
|  |             distance: hasLoginShown ? 0 : 0.7 | ||||||
|  |             userName: get_name(1) | ||||||
|  |             userLogin: get_login(1) | ||||||
|  |             userAvatar: get_avatar(1) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: botFarItem | ||||||
|  |             y: pageRoot.height / 1.10 | ||||||
|  |             distance: hasLoginShown ? 0 : 0.4 | ||||||
|  |             userName: get_name(2) | ||||||
|  |             userLogin: get_login(2) | ||||||
|  |             userAvatar: get_avatar(2) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         LoopListUserItem | ||||||
|  |         { | ||||||
|  |             id: botFallbackItem | ||||||
|  |             y: pageRoot.height | ||||||
|  |             distance: 0 | ||||||
|  |             userName: get_name(3) | ||||||
|  |             userLogin: get_login(3) | ||||||
|  |             userAvatar: get_avatar(3) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         TextField | ||||||
|  |         { | ||||||
|  |             id: passwordField | ||||||
|  |             y: hasLoginShown ? pageRoot.height / 2.3 + 35 : pageRoot.height / 2.3 + 60 | ||||||
|  |             width: parent.width | ||||||
|  |             opacity: hasLoginShown ? 1 : 0 | ||||||
|  | 
 | ||||||
|  |             placeholderText: localeText.password | ||||||
|  |             echoMode: TextInput.Password | ||||||
|  | 
 | ||||||
|  |             style: TextFieldStyle | ||||||
|  |             { | ||||||
|  |                 textColor: "#dddddd" | ||||||
|  |                 placeholderTextColor: "#888888" | ||||||
|  |                 background: Item { height: 25 } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             font | ||||||
|  |             { | ||||||
|  |                 family: "Roboto" | ||||||
|  |                 bold: true | ||||||
|  |                 pointSize: 18 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Component.onCompleted: forceActiveFocus() | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Rectangle | ||||||
|  |         { | ||||||
|  |             id: progressBar | ||||||
|  |             y: hasLoginShown ? pageRoot.height / 2.3 + 70 : pageRoot.height / 2.3 + 105 | ||||||
|  |             width: parent.width | ||||||
|  |             height: 2 | ||||||
|  |             opacity: hasLoginShown ? 1 : 0 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Rectangle | ||||||
|  |         { | ||||||
|  |             id: progressBarSlider1 | ||||||
|  |             x: 0 | ||||||
|  |             y: progressBar.y | ||||||
|  |             width: parent.width / 5 | ||||||
|  |             height: 2 | ||||||
|  |             opacity: 0 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Rectangle | ||||||
|  |         { | ||||||
|  |             id: progressBarSlider2 | ||||||
|  |             x: parent.width | ||||||
|  |             y: progressBar.y | ||||||
|  |             width: 0 | ||||||
|  |             height: 2 | ||||||
|  |             opacity: 0 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonUserLogin | ||||||
|  |             x: userListContainer.width - widthFull | ||||||
|  |             y: hasLoginShown ? pageRoot.height / 2.3 + 74 : pageRoot.height / 2.3 + 109 | ||||||
|  |             paddingTop: 2 | ||||||
|  |             selected: true | ||||||
|  |             opacity: hasLoginShown ? 1 : 0 | ||||||
|  | 
 | ||||||
|  |             text: localeText.login | ||||||
|  | 
 | ||||||
|  |             onClicked: select_or_login() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SlicedButton | ||||||
|  |         { | ||||||
|  |             id: buttonUserBack | ||||||
|  |             x: userListContainer.width - widthFull - buttonUserLogin.widthPartial - 3 | ||||||
|  |             y: hasLoginShown ? pageRoot.height / 2.3 + 74 : pageRoot.height / 2.3 + 109 | ||||||
|  |             paddingTop: 2 | ||||||
|  |             opacity: hasLoginShown ? 1 : 0 | ||||||
|  | 
 | ||||||
|  |             text: qsTr("Back") | ||||||
|  | 
 | ||||||
|  |             onClicked: back_to_selection() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Label | ||||||
|  |         { | ||||||
|  |             id: errorMessage | ||||||
|  |             text: localeText.loginFailed | ||||||
|  |             anchors.horizontalCenter: parent.horizontalCenter | ||||||
|  |             y: pageRoot.height / 4.7 | ||||||
|  |             opacity: 0 | ||||||
|  | 
 | ||||||
|  |             color: "#fff" | ||||||
|  | 
 | ||||||
|  |             font | ||||||
|  |             { | ||||||
|  |                 family: "Roboto" | ||||||
|  |                 bold: true | ||||||
|  |                 pointSize: 18 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Behavior on opacity { NumberAnimation { duration: userListContainer.scrollDuration } } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: progressBarLoop | ||||||
|  |             loops: Animation.Infinite | ||||||
|  |             SequentialAnimation | ||||||
|  |             { | ||||||
|  |                 NumberAnimation { target: progressBarSlider1; property: "x"; to: userListContainer.width - userListContainer.width / 5; duration: 400 } | ||||||
|  |                 ParallelAnimation | ||||||
|  |                 { | ||||||
|  |                     NumberAnimation { target: progressBarSlider1; property: "x"; to: userListContainer.width; duration: 100 } | ||||||
|  |                     NumberAnimation { target: progressBarSlider1; property: "width"; to: 0; duration: 100 } | ||||||
|  |                 } | ||||||
|  |                 NumberAnimation { target: progressBarSlider1; property: "x"; to: 0; duration: 500 } | ||||||
|  |                 NumberAnimation { target: progressBarSlider1; property: "width"; to: userListContainer.width / 5; duration: 100 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             SequentialAnimation | ||||||
|  |             { | ||||||
|  |                 NumberAnimation { target: progressBarSlider2; property: "x"; to: 0; duration: 500 } | ||||||
|  |                 NumberAnimation { target: progressBarSlider2; property: "width"; to: userListContainer.width / 5; duration: 100 } | ||||||
|  |                 NumberAnimation { target: progressBarSlider2; property: "x"; to: userListContainer.width - userListContainer.width / 5; duration: 400 } | ||||||
|  |                 ParallelAnimation | ||||||
|  |                 { | ||||||
|  |                     NumberAnimation { target: progressBarSlider2; property: "x"; to: userListContainer.width; duration: 100 } | ||||||
|  |                     NumberAnimation { target: progressBarSlider2; property: "width"; to: 0; duration: 100 } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             onStopped:  | ||||||
|  |             { | ||||||
|  |                 progressBarSlider1.x = 0 | ||||||
|  |                 progressBarSlider1.width = userListContainer.width / 5 | ||||||
|  |                 progressBarSlider2.x = userListContainer.width | ||||||
|  |                 progressBarSlider2.width = 0 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: userListHideOther | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 2.3 - 40; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: passwordField; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: passwordField; property: "y"; to: pageRoot.height / 2.3 + 35; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "y"; to: pageRoot.height / 2.3 + 70; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "y"; to: pageRoot.height / 2.3 + 74; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "y"; to: pageRoot.height / 2.3 + 74; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped:  | ||||||
|  |             { | ||||||
|  |                 hasLoginShown = true | ||||||
|  |                 passwordField.forceActiveFocus() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: userListShowOther | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 2.3; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: passwordField; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: passwordField; property: "y"; to: pageRoot.height / 2.3 + 60; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "y"; to: pageRoot.height / 2.3 + 105; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "y"; to: pageRoot.height / 2.3 + 109; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "y"; to: pageRoot.height / 2.3 + 109; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 hasLoginShown = false | ||||||
|  |                 pageRoot.focus = true | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: userListScrollUp | ||||||
|  |             NumberAnimation { target: topFarItem; property: "y"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |              | ||||||
|  |             NumberAnimation { target: topMidItem; property: "y"; to: pageRoot.height / 18; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 4.7; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botMidItem; property: "y"; to: pageRoot.height / 2.3; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFarItem; property: "y"; to: pageRoot.height / 1.45; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFallbackItem; property: "y"; to: pageRoot.height / 1.10; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFallbackItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 if (selectedIndex >= userModel.count - 1) | ||||||
|  |                     selectedIndex = 0 | ||||||
|  |                 else | ||||||
|  |                     selectedIndex++ | ||||||
|  | 
 | ||||||
|  |                 reset_items() | ||||||
|  | 
 | ||||||
|  |                 if (scrollRepeat > 0) | ||||||
|  |                 { | ||||||
|  |                     scrollRepeat-- | ||||||
|  |                     userListScrollUp.start() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: userListScrollDown | ||||||
|  |             NumberAnimation { target: topFallbackItem; property: "y"; to: pageRoot.height / 18; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFallbackItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: topFarItem; property: "y"; to: pageRoot.height / 4.7; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topFarItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  |              | ||||||
|  |             NumberAnimation { target: topMidItem; property: "y"; to: pageRoot.height / 2.3; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: topMidItem; property: "distance"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 1.45; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "distance"; to: 0.7; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botMidItem; property: "y"; to: pageRoot.height / 1.10; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botMidItem; property: "distance"; to: 0.4; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             NumberAnimation { target: botFarItem; property: "y"; to: pageRoot.height; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: botFarItem; property: "distance"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 if (selectedIndex <= 0) | ||||||
|  |                     selectedIndex = userModel.count - 1 | ||||||
|  |                 else | ||||||
|  |                     selectedIndex-- | ||||||
|  |                  | ||||||
|  |                 reset_items() | ||||||
|  | 
 | ||||||
|  |                 if (scrollRepeat > 0) | ||||||
|  |                 { | ||||||
|  |                     scrollRepeat-- | ||||||
|  |                     userListScrollDown.start() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: loginEnterAnimation | ||||||
|  |             NumberAnimation { target: passwordField; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "opacity"; to: 0.5; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBarSlider1; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBarSlider2; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 2.3 - 15; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ParallelAnimation | ||||||
|  |         { | ||||||
|  |             id: loginExitAnimation | ||||||
|  |             NumberAnimation { target: passwordField; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserBack; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: buttonUserLogin; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBar; property: "opacity"; to: 1; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBarSlider1; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: progressBarSlider2; property: "opacity"; to: 0; duration: userListContainer.scrollDuration } | ||||||
|  |             NumberAnimation { target: middleItem; property: "y"; to: pageRoot.height / 2.3 - 40; duration: userListContainer.scrollDuration } | ||||||
|  | 
 | ||||||
|  |             onStopped: | ||||||
|  |             { | ||||||
|  |                 progressBarLoop.stop() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function reset_items() | ||||||
|  |     { | ||||||
|  |         topFallbackItem.y = 0 | ||||||
|  |         topFallbackItem.distance = 0 | ||||||
|  | 
 | ||||||
|  |         topFarItem.y = pageRoot.height / 18 | ||||||
|  |         topFarItem.distance = 0.4 | ||||||
|  | 
 | ||||||
|  |         topMidItem.y = pageRoot.height / 4.7 | ||||||
|  |         topMidItem.distance = 0.7 | ||||||
|  | 
 | ||||||
|  |         middleItem.y = pageRoot.height / 2.3 | ||||||
|  |         middleItem.distance = 1 | ||||||
|  | 
 | ||||||
|  |         botMidItem.y = pageRoot.height / 1.45 | ||||||
|  |         botMidItem.distance = 0.7 | ||||||
|  | 
 | ||||||
|  |         botFarItem.y = pageRoot.height / 1.10 | ||||||
|  |         botFarItem.distance = 0.4 | ||||||
|  | 
 | ||||||
|  |         botFallbackItem.y = pageRoot.height | ||||||
|  |         botFallbackItem.distance = 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_up() | ||||||
|  |     { | ||||||
|  |         if (!hasLoginShown) | ||||||
|  |             userListScrollUp.start() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function scroll_down() | ||||||
|  |     { | ||||||
|  |         if (!hasLoginShown) | ||||||
|  |             userListScrollDown.start() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function select_or_login() | ||||||
|  |     { | ||||||
|  |         if (hasLoginShown) | ||||||
|  |         { | ||||||
|  |             errorMessage.opacity = 0 | ||||||
|  |             pageRoot.lockNav() | ||||||
|  |             pageRoot.enabled = false | ||||||
|  |             progressBarLoop.start() | ||||||
|  |             loginEnterAnimation.start() | ||||||
|  |             sddm.login(currentUserLogin, passwordField.text, selectedSessionIndex) | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             userListHideOther.start() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function back_to_selection() | ||||||
|  |     { | ||||||
|  |         if (hasLoginShown) | ||||||
|  |         { | ||||||
|  |             userListShowOther.start() | ||||||
|  |             errorMessage.opacity = 0 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Keys.onUpPressed: scroll_down() | ||||||
|  |     Keys.onDownPressed: scroll_up() | ||||||
|  |     Keys.onEnterPressed: select_or_login() | ||||||
|  |     Keys.onReturnPressed: select_or_login() | ||||||
|  |     Keys.onEscapePressed: back_to_selection() | ||||||
|  | 
 | ||||||
|  |     MouseArea | ||||||
|  |     { | ||||||
|  |         id: listMouseArea | ||||||
|  |         anchors.fill: parent | ||||||
|  |         propagateComposedEvents: true | ||||||
|  |         onWheel: | ||||||
|  |         { | ||||||
|  |             if (!hasLoginShown) | ||||||
|  |             { | ||||||
|  |                 if (wheel.pixelDelta.y < 0) | ||||||
|  |                     scroll_up() | ||||||
|  |                 else | ||||||
|  |                     scroll_down() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										237
									
								
								slice/SlicedButton.qml
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,237 @@ | ||||||
|  | import QtQuick 2.7 | ||||||
|  | import QtQuick.Controls 1.4 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Item | ||||||
|  | { | ||||||
|  |     id: buttonRoot | ||||||
|  |     height: 25 | ||||||
|  | 
 | ||||||
|  |     property int fontSize: 13 | ||||||
|  |     property string text: "" | ||||||
|  | 
 | ||||||
|  |     property bool hasLeftSlice: true | ||||||
|  |     property bool hasRightSlice: true | ||||||
|  | 
 | ||||||
|  |     property bool selected: false | ||||||
|  |     readonly property int skew: 15 | ||||||
|  | 
 | ||||||
|  |     readonly property int paddingLeft: hasLeftSlice ? skew : 5 | ||||||
|  |     property int paddingTop: 3 | ||||||
|  |     readonly property int paddingRight: hasRightSlice ? skew : 5 | ||||||
|  | 
 | ||||||
|  |     readonly property int widthFull: buttonText.width + paddingLeft + paddingRight | ||||||
|  |     readonly property int widthPartial: buttonText.width + paddingLeft | ||||||
|  | 
 | ||||||
|  |     signal clicked() | ||||||
|  | 
 | ||||||
|  |     Behavior on x | ||||||
|  |     { | ||||||
|  |         PropertyAnimation { duration: 100 } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onSelectedChanged: | ||||||
|  |     { | ||||||
|  |         buttonBgSliceLeft.requestPaint() | ||||||
|  |         buttonBgSliceRight.requestPaint() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     onTextChanged: | ||||||
|  |     { | ||||||
|  |         buttonText.text = buttonRoot.text | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     state: "idle" | ||||||
|  |     states: | ||||||
|  |     [ | ||||||
|  |         State | ||||||
|  |         { | ||||||
|  |             name: "idle" | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgSliceLeft; | ||||||
|  |                 bgColor: selected ? "#dddddd" : "#888888" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgCenter; | ||||||
|  |                 color: selected ? "#dddddd" : "#888888" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgSliceRight; | ||||||
|  |                 bgColor: selected ? "#dddddd" : "#888888" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         State | ||||||
|  |         { | ||||||
|  |             name: "hover" | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgSliceLeft; | ||||||
|  |                 bgColor: selected ? "#cccccc" : "#aaaaaa" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgCenter; | ||||||
|  |                 color: selected ? "#cccccc" : "#aaaaaa" | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             PropertyChanges | ||||||
|  |             { | ||||||
|  |                 target: buttonBgSliceRight; | ||||||
|  |                 bgColor: selected ? "#cccccc" : "#aaaaaa" | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     Canvas | ||||||
|  |     { | ||||||
|  |         id: buttonBgSliceLeft | ||||||
|  | 
 | ||||||
|  |         width: paddingLeft | ||||||
|  |         height: parent.height | ||||||
|  |         property string bgColor: "#888888" | ||||||
|  | 
 | ||||||
|  |         onPaint: | ||||||
|  |         { | ||||||
|  | 
 | ||||||
|  |             var context = getContext("2d") | ||||||
|  |             context.clearRect(0, 0, width, height); | ||||||
|  |             context.fillStyle = bgColor | ||||||
|  | 
 | ||||||
|  |             context.beginPath() | ||||||
|  | 
 | ||||||
|  |             if (buttonRoot.hasLeftSlice) | ||||||
|  |                 context.moveTo(paddingLeft, 0) | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 context.moveTo(0, 0) | ||||||
|  |                 context.lineTo(paddingLeft, 0) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             context.lineTo(paddingLeft, height) | ||||||
|  |             context.lineTo(0, height) | ||||||
|  |              | ||||||
|  |             context.closePath() | ||||||
|  |             context.fill() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         Behavior on x | ||||||
|  |         { | ||||||
|  |             PropertyAnimation { duration: 100 } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Rectangle | ||||||
|  |     { | ||||||
|  |         id: buttonBgCenter | ||||||
|  |         color: "#888888" | ||||||
|  |         x: paddingLeft | ||||||
|  |         width: buttonText.width | ||||||
|  |         height: parent.height | ||||||
|  | 
 | ||||||
|  |         Behavior on width | ||||||
|  |         { | ||||||
|  |             PropertyAnimation | ||||||
|  |             { | ||||||
|  |                 duration: 100 | ||||||
|  |                 onStopped: | ||||||
|  |                 { | ||||||
|  |                     buttonRoot.showTextAnimation.start() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         Behavior on x | ||||||
|  |         { | ||||||
|  |             PropertyAnimation { duration: 100 } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Canvas | ||||||
|  |     { | ||||||
|  |         id: buttonBgSliceRight | ||||||
|  | 
 | ||||||
|  |         x: widthPartial | ||||||
|  | 
 | ||||||
|  |         width: paddingRight | ||||||
|  |         height: parent.height | ||||||
|  |         property string bgColor: "#888888" | ||||||
|  | 
 | ||||||
|  |         onPaint: | ||||||
|  |         { | ||||||
|  |             var context = getContext("2d") | ||||||
|  |             context.clearRect(0, 0, paddingRight, height); | ||||||
|  |             context.fillStyle = bgColor | ||||||
|  | 
 | ||||||
|  |             context.beginPath() | ||||||
|  | 
 | ||||||
|  |             context.moveTo(0, 0) | ||||||
|  |             context.lineTo(paddingRight, 0) | ||||||
|  | 
 | ||||||
|  |             if (!buttonRoot.hasRightSlice) | ||||||
|  |                 context.lineTo(paddingRight, height) | ||||||
|  |              | ||||||
|  |             context.lineTo(0, height) | ||||||
|  |              | ||||||
|  |             context.closePath() | ||||||
|  |             context.fill() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Behavior on x | ||||||
|  |         { | ||||||
|  |             PropertyAnimation { duration: 100 } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     Label | ||||||
|  |     { | ||||||
|  |         id: buttonText | ||||||
|  |         x: paddingLeft | ||||||
|  |         y: paddingTop | ||||||
|  |         color: "#1f1f1f" | ||||||
|  | 
 | ||||||
|  |         font | ||||||
|  |         { | ||||||
|  |             family: "Roboto" | ||||||
|  |             bold: true | ||||||
|  |             pointSize: fontSize | ||||||
|  |             capitalization: Font.AllUppercase | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         text: "" | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     MouseArea | ||||||
|  |     { | ||||||
|  |         width: widthFull | ||||||
|  |         height: parent.height | ||||||
|  | 
 | ||||||
|  |         cursorShape: Qt.PointingHandCursor | ||||||
|  |         hoverEnabled: true | ||||||
|  | 
 | ||||||
|  |         onEntered:  | ||||||
|  |         { | ||||||
|  |             buttonRoot.state = "hover" | ||||||
|  |             buttonBgSliceLeft.requestPaint() | ||||||
|  |             buttonBgSliceRight.requestPaint() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         onExited: | ||||||
|  |         { | ||||||
|  |             buttonRoot.state = "idle" | ||||||
|  |             buttonBgSliceLeft.requestPaint() | ||||||
|  |             buttonBgSliceRight.requestPaint() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         onClicked: buttonRoot.clicked() | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								slice/icons/arrow-left.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M20,10V14H11L14.5,17.5L12.08,19.92L4.16,12L12.08,4.08L14.5,6.5L11,10H20Z" /></svg> | ||||||
| After Width: | Height: | Size: 367 B | 
							
								
								
									
										1
									
								
								slice/icons/arrow-right.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,10V14H13L9.5,17.5L11.92,19.92L19.84,12L11.92,4.08L9.5,6.5L13,10H4Z" /></svg> | ||||||
| After Width: | Height: | Size: 364 B | 
							
								
								
									
										1
									
								
								slice/icons/hibernate.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M15,16H13V8H15M11,16H9V8H11M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" /></svg> | ||||||
| After Width: | Height: | Size: 398 B | 
							
								
								
									
										1
									
								
								slice/icons/hybrid-sleep.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M15,16H9V14L12.39,10H9V8H15V10L11.62,14H15V16M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z" /></svg> | ||||||
| After Width: | Height: | Size: 427 B | 
							
								
								
									
										1
									
								
								slice/icons/no_avatar.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" /></svg> | ||||||
| After Width: | Height: | Size: 421 B | 
							
								
								
									
										1
									
								
								slice/icons/power-off.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16.56,5.44L15.11,6.89C16.84,7.94 18,9.83 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12C6,9.83 7.16,7.94 8.88,6.88L7.44,5.44C5.36,6.88 4,9.28 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,9.28 18.64,6.88 16.56,5.44M13,3H11V13H13" /></svg> | ||||||
| After Width: | Height: | Size: 508 B | 
							
								
								
									
										1
									
								
								slice/icons/reboot.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,12H22.32L17.37,16.95L12.42,12H16.97C17,10.46 16.42,8.93 15.24,7.75C12.9,5.41 9.1,5.41 6.76,7.75C4.42,10.09 4.42,13.9 6.76,16.24C8.6,18.08 11.36,18.47 13.58,17.41L15.05,18.88C12,20.69 8,20.29 5.34,17.65C2.22,14.53 2.23,9.47 5.35,6.35C8.5,3.22 13.53,3.21 16.66,6.34C18.22,7.9 19,9.95 19,12Z" /></svg> | ||||||
| After Width: | Height: | Size: 587 B | 
							
								
								
									
										1
									
								
								slice/icons/suspend.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,16V8H15V16H13M9,16V8H11V16H9M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z" /></svg> | ||||||
| After Width: | Height: | Size: 470 B | 
							
								
								
									
										11
									
								
								slice/metadata.desktop
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,11 @@ | ||||||
|  | [SddmGreeterTheme] | ||||||
|  | Name=Slice | ||||||
|  | Description=Simple SDDM theme. | ||||||
|  | Author=RadRussianRus | ||||||
|  | Copyright=(c) 2018, RadRussianRus | ||||||
|  | License=CC-BY-SA | ||||||
|  | Type=sddm-theme | ||||||
|  | Website=https://github.com/RadRussianRus/slice-sddm | ||||||
|  | Version=1.0 | ||||||
|  | MainScript=Main.qml | ||||||
|  | TranslationsDirectory=translations | ||||||
							
								
								
									
										
											BIN
										
									
								
								slice/translations/ru.qm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										26
									
								
								slice/translations/ru.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,26 @@ | ||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!DOCTYPE TS> | ||||||
|  | <TS version="2.1" language="ru"> | ||||||
|  | <context> | ||||||
|  |     <name>PagePower</name> | ||||||
|  |     <message> | ||||||
|  |         <source>Suspend</source> | ||||||
|  |         <translation>Ждущий режим</translation> | ||||||
|  |     </message> | ||||||
|  |     <message> | ||||||
|  |         <source>Hibernate</source> | ||||||
|  |         <translation>Гибернация</translation> | ||||||
|  |     </message> | ||||||
|  |     <message> | ||||||
|  |         <source>Hybrid Sleep</source> | ||||||
|  |         <translation>Гибридный сон</translation> | ||||||
|  |     </message> | ||||||
|  | </context> | ||||||
|  | <context> | ||||||
|  |     <name>PageUsers</name> | ||||||
|  |     <message> | ||||||
|  |         <source>Back</source> | ||||||
|  |         <translation>Назад</translation> | ||||||
|  |     </message> | ||||||
|  | </context> | ||||||
|  | </TS>  | ||||||