From eaadaf9314e25e1527e16f73f25eec6f994e8207 Mon Sep 17 00:00:00 2001 From: zoran-vucenovic Date: Wed, 5 Sep 2012 08:30:42 +0000 Subject: [PATCH] Releasing version 1.4 git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2504 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../ZVDateTimeCtrls/tags/1.4/COPYING.LGPL | 481 +++ .../tags/1.4/COPYING.modifiedLGPL | 28 + .../ZVDateTimeCtrls/tags/1.4/ChangeLog.txt | 68 + .../ZVDateTimeCtrls/tags/1.4/ReadMe.htm | 426 +++ .../tags/1.4/dbzvdatetimepicker.pas | 282 ++ .../tags/1.4/pictures/TDBZVDateTimePicker.png | Bin 0 -> 443 bytes .../tags/1.4/pictures/TZVDateTimePicker.png | Bin 0 -> 353 bytes .../tags/1.4/pictures/ZVDateControls01.PNG | Bin 0 -> 1543 bytes .../tags/1.4/pictures/ZVDateControls02.PNG | Bin 0 -> 1009 bytes .../tags/1.4/pictures/ZVDateControls03.PNG | Bin 0 -> 1492 bytes .../1.4/pictures/ZVDateTimePickerEditor.PNG | Bin 0 -> 10848 bytes .../tags/1.4/zvdatetimecontrolsreg.pas | 49 + .../tags/1.4/zvdatetimectrls.lpk | 77 + .../tags/1.4/zvdatetimectrls.lrs | 33 + .../tags/1.4/zvdatetimectrls.pas | 22 + .../tags/1.4/zvdatetimepicker.pas | 3279 +++++++++++++++++ .../tags/1.4/zvdatetimepickerpropedit.pas | 495 +++ 17 files changed, 5240 insertions(+) create mode 100644 components/ZVDateTimeCtrls/tags/1.4/COPYING.LGPL create mode 100644 components/ZVDateTimeCtrls/tags/1.4/COPYING.modifiedLGPL create mode 100644 components/ZVDateTimeCtrls/tags/1.4/ChangeLog.txt create mode 100644 components/ZVDateTimeCtrls/tags/1.4/ReadMe.htm create mode 100644 components/ZVDateTimeCtrls/tags/1.4/dbzvdatetimepicker.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/TDBZVDateTimePicker.png create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/TZVDateTimePicker.png create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls01.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls02.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls03.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateTimePickerEditor.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimecontrolsreg.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.lpk create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.lrs create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimepicker.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.4/zvdatetimepickerpropedit.pas diff --git a/components/ZVDateTimeCtrls/tags/1.4/COPYING.LGPL b/components/ZVDateTimeCtrls/tags/1.4/COPYING.LGPL new file mode 100644 index 000000000..5bc8fb2c8 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/COPYING.LGPL @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/components/ZVDateTimeCtrls/tags/1.4/COPYING.modifiedLGPL b/components/ZVDateTimeCtrls/tags/1.4/COPYING.modifiedLGPL new file mode 100644 index 000000000..d576c67c3 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/COPYING.modifiedLGPL @@ -0,0 +1,28 @@ +The files in ZVDateControls package are under the modified LGPL, +same as the FPC RTL and the Lazarus LCL. + +Copyright (C) Zoran Vučenović, http://wiki.lazarus.freepascal.org/User:Zoran + +These files are distributed under the Library GNU General Public License +(see the file COPYING.LGPL) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules,and +to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a +module which is not derived from or based on this library. If you modify +this library, you may extend this exception to your version of the library, +but you are not obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +The ZVDateControls package is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License +for more details. + +You should have received a copy of the GNU Library General Public License +along with this library (file COPYING.LGPL); if not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + diff --git a/components/ZVDateTimeCtrls/tags/1.4/ChangeLog.txt b/components/ZVDateTimeCtrls/tags/1.4/ChangeLog.txt new file mode 100644 index 000000000..83a6cfd23 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/ChangeLog.txt @@ -0,0 +1,68 @@ +=================================================== +Version 1.0 -- 27. Feb. 2010. + +Initial release + +=================================================== + +Version 1.1 -- 18. April 2010. + +The Data aware control's (DBZVDateTimePicker's) interacting with DataSource is slightly improved. + +There are also several fixes, these are some of them. The first three fixes apply to DBZVDateTimePicker control only, the fourth, fifth and sixth apply to both controls. + +1. In runtime changing date/time in DBZVDateTimePicker was possible when not connected to database. + + When not connected to specific DB field, or when the Database connection is not active, now the control can only have NULL value, which is appropriate behaviour for a DB control. + +2. The Time property was accidentaly published in DBZVDateTimePicker. Time property, as well as Date, cannot be used directly in DBZVDateTimePicker, it is tied to underlying DB field. + + The Time property is removed from published section of TDBZVDateTimePicker. + +3. The DBZVDateTimePicker's properties MaxDate and MinDate were displayed as real numbers in Object inspector. + + They are now displayed as dates. + +4. The Hint property didn't work -- the hint didn't appear. + + Now the Hint is shown when mouse pointer is over the control, of course only if ShowHint is set to True. + +5. When calendar button is shown and AutoSize is False and the width is less than Text's width + SpeedButton's width, then the button gets hidden behind the text. + + Now, the button is shown in front of the text, which is more appropriate behaviour. + +6. When UpDown is shown and AutoSize is False, if Heigth is set to more than it would be if AutoSized, then, setting AutoSize to True would not trigger shirnking the control's Height as it should. + + Fixed, now it does. + +=================================================== + +Version 1.2 -- 12. May 2010. + +Because of changes in LCL, some changes in code were needed, so that controls can compile with new Lazarus from svn trunk (since revision 25204). + +=================================================== + +Version 1.3 -- 1. April 2011. + + The changes of LCL, made after separating the 0.9.30 branch from the trunk, caused the crash of the control in new Lazarus 0.9.31 from trunk (see: http://wiki.freepascal.org/Lazarus_0.99.0_release_notes#Changes_affecting_compatibility), internal using of constructor TForm.Create had to be replaced by TForm.CreateNew (it was used twice -- for the drop-down form which carries the calendar and for design-time component editor form). + There are also internal changes which improved autosizing of the control. + The code is much simplified and the control is lighter now (there used to be an auxiliary control which is removed now and its code is simplified and unified in the main control). + +=================================================== + +Version 1.4 -- 5. September 2012. + +These are main changes: + + The ZVDateTimeControls package is now in subversion control. + + Added an event to interact with CheckBox -- OnCheckBoxChange (by Daniel S. Almeida). + + OnChange event was triggered whenever date/time values change. Now it reacts only on changes made by user interaction, not when the changes are made programatically. The new behaviour is compatible with OnChange event of VCL's TDateTimePicker. + + In Linux, locale-dependent properties were not initialized to correct defaults. Fixed now. + + In Qt ws, the client rect of the control was not calculated correctly. Fixed now. + + Plus many internal changes... \ No newline at end of file diff --git a/components/ZVDateTimeCtrls/tags/1.4/ReadMe.htm b/components/ZVDateTimeCtrls/tags/1.4/ReadMe.htm new file mode 100644 index 000000000..430d07d32 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/ReadMe.htm @@ -0,0 +1,426 @@ + + + + + + + + + + + + +

ZVDateTimeControls +Package for Lazarus

+


+

+

http://wiki.lazarus.freepascal.org/ZVDateTimeControls_Package

+


+

+


+

+

The +ZVDateTimeControls package contains two controls:

+


+

+

+TZVDateTimePicker

+


+

+

+TDBZVDateTimePicker

+


+

+

Author

+

Zoran +Vučenović

+


+

+

License

+

+Modified LGPL, same as Lazarus +component library.

+


+

+

Introduction

+

Delphi's +VCL has a +control named TDateTimePicker, which I find very useful for +editing dates. LCL, however, does not have this control. Instead, for +editing dates LCL +has a control named TDateEdit, but I prefer the VCL's +TDateTimePicker.

+


+

+

Therefore, +I tried to create a cross-platform Lazarus control which would +resemble VCL's TDateTimePicker as much as possible.

+


+

+

The +TZVDateTimePicker control does not use native +Win control. It descends from LCL's TCustomControl to be +cross-platform. It has been tested on Windows with win32/64 and qt +widgetsets, as well as on Linux with qt and gtk2 widgetsets.

+


+

+

Note +that the TZVDateTimePicker control does not descend from TEdit, so it +does not have unnecessary caret. The VCL's control doesn't have caret +either.

+


+

+

Installation

+

To +install the package in Lazarus IDE follow these steps:

+


+

+
    +
      +
    1. Open + the package in Package Editor (in Lazarus' main menu click Package, + then Open package file... locate the file + zvdatetimectrls.lpk and click Open).

      +
    2. Compile + the package (click Compile in Package Editor's tool bar).

      +
    3. Install + the package in the IDE (click Install – you will be asked + if you want to rebuild Lazarus, click Yes. Wait until + Lazarus rebuilds and restarts itself. The new tab “Date and + Time Ctrls” appears on the component palette with + TZVDateTimePicker and TDBZVDateTimePicker controls.

      +
    +
+


+

+

Change +Log

+

+For more details about changes, see +ChangeLog.txt

+


+

+

+Version 1.0 – 27. February 2010.

+

+Version 1.1 – 17. April 2010.

+

+Version 1.2 – 12. May 2010.

+

+Version 1.3 – 1. April 2011.

+

+Version 1.4 – 4. September 2012.

+


+

+

TZVDateTimePicker +

+

+Properties:

+

+I'll explain some properties of +TZVDateTimePicker control: +

+

+
+

+

+DateTime: TDateTime (public)

+

The +DateTime value displayed on the control. This property is not +published in object inspector, but its value is actually the same as +Date and Time properties composed in one value. This property is +provided to allow setting or reading of both date and time value at +once in program code. In design time, Date and Time can be set in +object inspector. There +is also component editor which provides easy way of setting this +property in design time.

+

+
+

+

+Date: TDate

+

The +date displayed on the control which the user can edit.

+

+
+

+

+Time: TTime

+

The +time displayed on the control which the user can edit.

+

+
+

+

+MinDate: TDate

+

The +minimal date user can enter.

+


+

+

+MaxDate: TDate

+

The +maximal date user can enter.

+


+

+

+NullInputAllowed: Boolean

+

When +True, the user can set the date to NullDate constant by pressing N +key.

+


+

+

+CenturyFrom: Word

+

When +user enters the year in two-digit format, then the CenturyFrom +property is used to determine which century the year belongs to. The +default is 1941, which means that when two digit years is entered, it +falls in interval 1941 – 2040. Note that MinDate and MaxDate +properties can also have influence on the decision – for example, +if the CenturyFrom is set to 1941 and MaxDate to 31. 12. 2010, if +user enters year 23, it will be set to 1923, because it can’t be +2033, due to MaxDate limit.

+


+

+

+Kind: TDateTimeKind

+

type +TDateTimeKind = (dtkDate, dtkTime, dtkDateTime);

+

The +control displays only date, only time or both.

+

+


+

+

+DateMode: TDTDateMode

+

type +TDTDateMode = (dmComboBox, dmUpDown, dmNone);

+

When +DateMode is set to dmComboBox, there is a button on the right side of +the control. When user clicks the button, the +calendar control is shown, allowing the user to pick the date. +When set to dmUpDown, then UpDown buttons are shown.

+

In +my opinion the UpDown buttons aren't really useful in this control, +they are provided for compatibility with Delphi's TDateTimePicker. Up +and down keys can always serve for same purpose, so can mouse wheel.

+

In +the next picture the first control's DateMode is set to dmComboBox +and the second control's to dmUpDown.

+

+

If +DateMode is dmComboBox, when the user clicks on the button a calendar +drops down, allowing the user to pick a date.

+


+

+

Note: +if Kind property is set to dtkTime, the calendar control is +pointless. Therefore, if DateMode is dmComboBox, the UpDown is shown +instead.

+


+

+

+ShowCheckBox: Boolean

+

When +set, there is a check box on the left side of the control. When +unchecked, the display appears grayed and user interaction with the +date or time is not possible. (The control is still enabled, though, +only in sense that the check box remains enabled).

+

+



+

+

+Checked: Boolean

+

If +ShowCheckBox is set to True, this property determines whether the +check box is checked or not. If ShowCheckBox is False, this property +has no purpose and is automatically set to True.

+


+

+

+DateDisplayOrder: TDateDisplayOrder

+

type +TDateDisplayOrder = (ddoDMY, ddoMDY, ddoYMD, ddoTryDefault);

+

Defines +the order for displaying day, month and year part of the date. When +ddoTryDefault is set, then the controls tries to determine the order +from ShortDateFormat +global variable.

+

This +is similar to DateEdit's +DateOrder property.

+


+

+

+DateSeparator: String

+

Defines +the string used to separate date, month and year date parts. Setting +this property automatically sets the UseDefaultSeparators property to +False. To ensure that date and time separators are set to user's +system defaults, set UseDefaultSeparators property to True.

+


+

+

+TimeSeparator: String

+

Defines +the string used to separate hour, minute, second and millisecond time +parts. Setting this property automatically sets the +UseDefaultSeparators property to False. To ensure that date and time +separators are set to user's system defaults, set +UseDefaultSeparators property to True.

+


+

+

+UseDefaultSeparators: Boolean

+

When +this property is set to True, then the DateSeparator and +TimeSeparator properties will be set to DateSeparator +and TimeSeparator +global variables, which are set to user system defaults when +application initializes.

+


+

+

+TrailingSeparator: Boolean

+

When +set to True, then the DateSeparator is shown once more, after the +last date part. This property exists because in some languages the +correct date format is 31. 1. 2010. including the last point, +after the year.

+


+

+

+LeadingZeros: Boolean

+

Determines +whether the date and time parts are displayed with or without leading +zeros (this actually affects day, month and hour parts of date and +time display).

+


+

+

+TimeDisplay: TTimeDisplay

+

type +TTimeDisplay = (tdHM, tdHMS, tdHMSMs);

+

If +Kind is dtkTime or dtkDateTime, then TimeDisplay value of tdHM means +that only hours and minutes are displayed, tdHMS adds displaying of +seconds and value of tdHMSMs means that milliseconds are displayed +too.

+


+

+

+TimeFormat: TTimeFormat

+

type +TTimeFormat = (tf12, tf24);

+

The +value of tf12 sets the display of time to 12 hours format, with AM/PM +string and tf24 sets to 24 hours format.

+


+

+

+TextForNullDate: String

+

Text +which appears when the null date is set and control does not have +focus. When control is focused, the text changes to defined format, +but displaying zeros for date, and nines for time (for example +"00/00/0000 99:99:99"), which is appropriate to user input. +User can set the date to NullDate by pressing N key, provided +NullInputAllowed +property is True.

+

When +TextForNullDate is set to empty string, zeros/nines format is +displayed even when control does not have focus. If you want empty +display, this can be acchieved by setting TextForNullDate to one or +more space characters.

+


+

+

+TDBZVDateTimePicker +

+

+TDBZVDateTimePicker is a data-aware +version of TZVDateTimePicker, with nice way of handling null database +values.

+


+

+

+Displaying null values +

+
+
+
When + the underlying DB field has null value, then:
+
+
    +
      +
    • + When the control gets focus, the + text changes to defined format, but displaying zeros for date parts + and nines for time parts (for example "00/00/0000 99:99:99"), + which is appropriate to user input.
    • + When the control + is not focused, then it displays the text defined in + TextForNullDate + property. The default is "NULL".
    +
+

+Setting the field value to null +

+
+
+
If + NullInputAllowed + property is True, the user can set the date and time to null, by + pressing N key. +
+
+

+ZVDateTimePicker +Editor

+

+

+

+ZVDateTimePicker Editor is a dialog +which provides easy way to set Date, Time, MinDate and MaxDate +properties in design time. It is invoked when ZVDateTimePicker +control is double-clicked in form designer. It is also shown when the +elipsis (…) button, shown in Date, Time, MinDate and MaxDate +properties in Object inspector, gets clicked.

+

+
+

+

Tips

+

+Q: When the date/time value is +null, how to display zeros/nines in user format, no matter whether +the control is focused or not?

+

+A: +Set TextForNullDate +property to empty string. If TextForNullDate is set to empty string, +then zeros/nines are displayed, same as when the control has focus.

+

+
+

+

+Q: +When the date/time +value is null, If empty string in TextForNullDate +property actually sets the display to zeros/nines format, how to set +the control to display nothing?

+

+A: +Set TextForNullDate +property to one space character, you will get the empty display.

+ + \ No newline at end of file diff --git a/components/ZVDateTimeCtrls/tags/1.4/dbzvdatetimepicker.pas b/components/ZVDateTimeCtrls/tags/1.4/dbzvdatetimepicker.pas new file mode 100644 index 000000000..49e0eb502 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/dbzvdatetimepicker.pas @@ -0,0 +1,282 @@ +{ +TDBZVDateTimePicker control for Lazarus +- - - - - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + +Last change: August 2012 + +This unit is part of ZVDateTimeCtrls package for Lazarus. +TDBZVDateTimePicker is data-aware version of TZVDateTimePicker control. + +----------------------------------------------------------- +LICENCE +- - - - + Modified LGPL -- see the file COPYING.modifiedLGPL. + +----------------------------------------------------------- +NO WARRANTY +- - - - - - + There is no warranty whatsoever. + +----------------------------------------------------------- +BEST REGARDS TO LAZARUS COMMUNITY! +- - - - - - - - - - - - - - - - - - + I do hope this control will be useful. +} +unit DBZVDateTimePicker; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, ZVDateTimePicker, db, DBCtrls; + +type + + { TDBZVDateTimePicker } + + TDBZVDateTimePicker = class(TCustomZVDateTimePicker) + private + { Private declarations } + FDataLink: TFieldDataLink; + FReadOnly: Boolean; + FDataChangeCount: Integer; + FChangingCount: Integer; + function GetDataField: string; + function GetDataSource: TDataSource; + procedure SetDataField(const AValue: string); + procedure SetDataSource(const AValue: TDataSource); + procedure DataChange(Sender: TObject); + procedure SetReadOnly(const AValue: Boolean); + procedure UpdateData(Sender: TObject); + procedure ActiveChange(Sender: TObject); + function GetField: TField; + procedure CheckField; + protected + { Protected declarations } + procedure Change; override; + procedure ConfirmChanges; override; + procedure UndoChanges; override; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + property Field: TField read GetField; + published + { Published declarations } + property DataField: string read GetDataField write SetDataField; + property DataSource: TDataSource read GetDataSource write SetDataSource; + property ReadOnly: Boolean read FReadOnly write SetReadOnly; + + property ArrowShape; + property ShowCheckBox; + property Checked; + property CenturyFrom; + property DateDisplayOrder; + property MaxDate; + property MinDate; + property AutoSize; + property Font; + property ParentFont; + property TabOrder; + property TabStop; + property BorderStyle; + property BorderSpacing; + property Enabled; + property Color; + property ParentColor; + property DateSeparator; + property TrailingSeparator; + property TextForNullDate; + property LeadingZeros; + property ShowHint; + property ParentShowHint; + property Align; + property Anchors; + property Constraints; + property Cursor; + property PopupMenu; + property Visible; + property NullInputAllowed; + property Kind; + property TimeSeparator; + property TimeFormat; + property TimeDisplay; + { property Time; This property should NOT be published here, it was + accidentally added in first release. } + property DateMode; + property UseDefaultSeparators; + //events: + property OnChange; + property OnCheckBoxChange; + property OnDropDown; + property OnCloseUp; + property OnChangeBounds; + property OnClick; + property OnContextPopup; + property OnDblClick; + property OnEditingDone; + property OnEnter; + property OnExit; + property OnKeyDown; + property OnKeyPress; + property OnKeyUp; + property OnMouseDown; + property OnMouseEnter; + property OnMouseMove; + property OnMouseUp; + property OnMouseLeave; + property OnResize; + property OnUTF8KeyPress; + end; + +implementation + +{ TDBZVDateTimePicker } + +function TDBZVDateTimePicker.GetDataField: string; +begin + Result := FDataLink.FieldName; +end; + +function TDBZVDateTimePicker.GetDataSource: TDataSource; +begin + Result := FDataLink.DataSource; +end; + +procedure TDBZVDateTimePicker.SetDataField(const AValue: string); +begin + FDataLink.FieldName := AValue; + CheckField; +end; + +procedure TDBZVDateTimePicker.SetDataSource(const AValue: TDataSource); +begin + ChangeDataSource(Self, FDataLink, AValue); + CheckField; +end; + +procedure TDBZVDateTimePicker.DataChange(Sender: TObject); +begin + if (FChangingCount = 0) then begin + Inc(FDataChangeCount); + try + if Assigned(FDataLink.Field) and not FDataLink.Field.IsNull then begin + // Using the SetTheDateJumpMinMax procedure, instead of property + SetDateTimeJumpMinMax(FDataLink.Field.AsDateTime); // assignment allows + // this control to display dates from database whose value falls + // outside of MinDate and MaxDate interval. + // Note that user still cannot enter such values in the control. + end else + DateTime := NullDate; + + finally + Dec(FDataChangeCount); + end; + end; +end; + +procedure TDBZVDateTimePicker.SetReadOnly(const AValue: Boolean); +begin + if FReadOnly <> AValue then begin + FReadOnly := AValue; + CheckField; + end; +end; + +procedure TDBZVDateTimePicker.UpdateData(Sender: TObject); +begin + if Assigned(FDataLink.Field) then begin + if DateIsNull then + FDataLink.Field.AsVariant := Null + else + FDataLink.Field.AsDateTime := DateTime; + end; +end; + +procedure TDBZVDateTimePicker.ActiveChange(Sender: TObject); +begin + CheckField; +end; + +function TDBZVDateTimePicker.GetField: TField; +begin + Result := FDataLink.Field; +end; + +procedure TDBZVDateTimePicker.CheckField; +begin + if (FDataLink.Active) and Assigned(FDataLink.Field) then + inherited ReadOnly := FReadOnly or (not FDataLink.CanModify) + else begin + inherited ReadOnly := True; + DateTime := NullDate; + end; +end; + +procedure TDBZVDateTimePicker.Change; +begin + if (FDataChangeCount <= 0) and Assigned(FDataLink) then begin + Inc(FChangingCount); + try + if FDataLink.Edit then begin + FDataLink.Modified; + inherited Change; // calls OnChange event handler + end else + FDataLink.Reset; // reverts user changes + finally + Dec(FChangingCount); + end; + end; +end; + +procedure TDBZVDateTimePicker.ConfirmChanges; +begin + inherited ConfirmChanges; + + if Assigned(FDataLink) then + try + FDataLink.UpdateRecord; + except + SetFocus; + raise; + end; + +end; + +procedure TDBZVDateTimePicker.UndoChanges; +begin + FDataLink.Reset; + + inherited UndoChanges; +end; + +constructor TDBZVDateTimePicker.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + + FDataChangeCount := 0; + FChangingCount := 0; + FDataLink := TFieldDataLink.Create; + FDataLink.Control := Self; + DateTime := NullDate; + FDataLink.OnActiveChange := @ActiveChange; + FDataLink.OnDataChange := @DataChange; + FDataLink.OnUpdateData := @UpdateData; + + CheckField; +end; + +destructor TDBZVDateTimePicker.Destroy; +begin + FDataLink.OnUpdateData := nil; + FDataLink.OnDataChange := nil; + FDataLink.OnActiveChange := nil; + FreeAndNil(FDataLink); + + inherited Destroy; +end; + +end. diff --git a/components/ZVDateTimeCtrls/tags/1.4/pictures/TDBZVDateTimePicker.png b/components/ZVDateTimeCtrls/tags/1.4/pictures/TDBZVDateTimePicker.png new file mode 100644 index 0000000000000000000000000000000000000000..36c68e7c9782fa22c8d919adc02a5c316a2cf2da GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj>?NMQuI#s%#W@TmBdzML0)@m& zTq8KgfF;t3vaHW+qwX z-%TmpG1`5HbQyNaMawAsZqbo%&|%DMiwuaf>s0bF=y2%jU{%<9e!hKMvOxXcwznMK z8(0O;FgZIX?~%C4R9$WTM(hEX(yE^f;Q|K>Qd1xQU$shW&W=Tkn3efDxEB5Xp8tRT zwy&0fCT9X9+&WVNf{uu}D4ac##1o#(d?HmyQJ%qgTe~DWM4f?RcCq literal 0 HcmV?d00001 diff --git a/components/ZVDateTimeCtrls/tags/1.4/pictures/TZVDateTimePicker.png b/components/ZVDateTimeCtrls/tags/1.4/pictures/TZVDateTimePicker.png new file mode 100644 index 0000000000000000000000000000000000000000..0d7c98d5691dae2b544432815dcfa28a9f4a6696 GIT binary patch literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj>?NMQuI#s%#W_?Y^ZI8T1PY0l zxJHx&=ckpFCl;kLxcj&OjZr8|EmAPnGbwCc@(`$mqolyk9VlZAWHWd*XvzaAmUKs7 zM+SzC{oH>NS%Lg>o-U3d6?5)RG2~-X6mYeimag<|cEH6;Q59@@32%6gU6YQ;$y{39 za`E5>#S{etr-hUE{7Dghc3%Dv*GF+vU+Wi~nHzNa(=HXitI?FsSnKE&xpZTrz%5~( zfX$q9iWAnZy;R_*$$D&tRr58`#LY9-IP&;~IKP|Z*<88rU|MyOqpBkBjtRlRY`+iB zUFyrGdQUd&(fhkX36J{^onUz&IcdRd*(YUli}u*rp5-js?I$|hSeRkw>yn~rj%SZJ s&X&J*Vfr6kSLQWe(vL38_^|malaWA&^yO5cG?0%yUHx3vIVCg!06Ua}7ytkO literal 0 HcmV?d00001 diff --git a/components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls01.PNG b/components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls01.PNG new file mode 100644 index 0000000000000000000000000000000000000000..096632fac5f0c3902ea36a232f0be86dd2c96cf3 GIT binary patch literal 1543 zcmV+i2Kf1jP)Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU%g-Jv~RCr$PoJ(sIK@foBpYR{}FZ=-_coYx*02L%4cun-+ML`if z1@xk#x2PZy4_$QxGEdX?cVnA?y|K4t{HR5`uQH%5vmFA(~6%bf!R6!EtL3^PX z5JFI82Vt!=Ff@GZ%(cGbmwn~vslf|39`CjH#!h*lKOIS{uHyxe3v;x>{b&MNyx# zsvA}?Y)8x6ZJF}QnmCrPo(M8kKTO?hW=uU5#f^>i-LeMd?75q&g7s!IZqy_A$(oCz zy~@&3B-W{O1#oC(rf94}XFqt69>pm}ta96KdlVJ67!azW*PG2oqh5|mbDg26D^2WX z#LSuayGhZx+jA(Unx?S<;M!Fbw6wf1-2sX|0Gu5Xqbaf7 zF+_XpiD*90S6NDhN`2t=FSUw79%5m6sx6CMHFu7uvizcI-06 z#NqfWUQt9^08AACiS=4-B`Pm0%}?f{n3fa$i@$XR(x z6Gd?sSlL%<)l#`Mw>bYJFGY-kc4+i%O?o8Io7)ER{ndyiD5j6-i#PPv&FR@U3OyHJ zl%?ZhC0dT6B`6U8psp9VxUz%r=dbCnxhOIhxQJ!2zCP{o%<=cODEspZNUNF5{oyjDLFl?8V55 z{@WLCJ`#%i2qSaX+uQA}*4ov(PZOVM^xt~iZa0NuW>W{(PF4LeDLpP|8`=p&@A zb7t<7^jU$!j9y7JQJ-1$HD~Lr{_1Q?TqF=eZ+OC=xYI~H+nj6m*OU8utKRIKVPSFk?&e)UKCuc`x_N*_F#BtNk z1v|%gY~TwvP(A+JHCVpLF^$M%vw-vM3;hnTR@%?_Z&e76i7`m*n=mBT(K1AZgQTgljhyGfShD3=t;)zFC`fPx#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU#Z%IT!RA@u(noVmHK^VvDm+<7J2S0#!KY$1xJctKBfGpg z7ln%8sh|h7=&dS9#Y3r}MG$O@H1#D((~6C=yV+!uHtIipU>No-+ud$U(^>w9 z$?#-$=a*;y^XyJeY4u+t@<@pQ;7X-LU?in+<*yn;38)imU4dw9KD65EFx*{ zacqIZ4I*pX*6_iF6?FSYCs>Z%G>wLW$fR(6$&NlB1=)7H6#|!MwCE4$L+$3%;N^ zYnofov_mqNL!p=`BSeNvG)<5tiEZ0v%uv)?F)3VH!H6bSFc(>@mEmw*sY*bjXRZrb zcnTjNT+?hojBP`lFE!9(7@DS5s^xrAxKtZ(ree;5Y_Hcl+RRM?)c2ksTQJRSh%r<| zeR00@(J)j^-K>^#N#O>$0g*+ya)fYQbdrE}EodAfIFi7Zw{^X)D&vd-n=_NxO*IxAnA>oQY&tjekX-XPYP6Z(F!J#4S_4J zS6-9l#e<88t32>6wm5Wg-^bp5rX&9c_ML~ENvt6b00000NkvXXu0mjfb_CL& literal 0 HcmV?d00001 diff --git a/components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls03.PNG b/components/ZVDateTimeCtrls/tags/1.4/pictures/ZVDateControls03.PNG new file mode 100644 index 0000000000000000000000000000000000000000..2e39777102bca96b328b6a36ba1cb1c24560da0e GIT binary patch literal 1492 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 xM|D}2!TDIC{}h=+tK9vg{zV@8$D=;rU& + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ExternHelp Items="Count"/> + + + diff --git a/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.lrs b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.lrs new file mode 100644 index 000000000..1c4b665d4 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.lrs @@ -0,0 +1,33 @@ +LazarusResources.Add('TZVDateTimePicker','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#7'tIME'#7#218#3#23#8'$'#25'n'#143#152#193#0#0#0#23'tEXtSoftware'#0'GLDP' + +'NG ver 3.4q'#133#164#225#0#0#0#8'tpNGGLD3'#0#0#0#0'J'#128')'#31#0#0#0#4'gAM' + +'A'#0#0#177#143#11#252'a'#5#0#0#0#206'IDATx'#156#221#148'1'#14#2'!'#16'E9' + +#150'g"'#246#155'P'#209#210'Zx'#6'.`'#236#12#198#214#27'Xli'#165'{'#132#209 + +#193#176'!d 0B'#161#147#188#252'd'#19#230#207#31#194#10#241#23'5M;'#232#9'i' + +#176','#143'f'#210's'#238'|)'#27'h'#173'AJY'#165#177#129#16#218#19#12'P'#179 + +#9#156's`'#173#173#210'pN)'#5#198#152':'#131#214#21'a'#179#152#172'A'#12'NTC' + +#238#146'I'#131'y'#190#193'f{bA%!'#13#184#144'SS'#6#251#195#157#165'M'#6'%' + +#222#29'V'#226#239#221#18'`'#227#143#194#200#4#224#25#146#160#219#29#228'v' + +#157'r'#188'>='#205#9'r'#187'N'#21#155'3'#19#0#185#235'tr'#150'A'#205#196'A' + +#155#31#218#208#151#252'-E'#3#172#244'g'#197#161'h'#240#179#245#2'2'#16#136 + +#27#211'e'#18'f'#0#0#0#0'IEND'#174'B`'#130 +]); +LazarusResources.Add('TDBZVDateTimePicker','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#6#0#0#0#224'w='#248#0 + +#0#0#7'tIME'#7#218#3#23#8'1'#25'Y:~'#213#0#0#0#23'tEXtSoftware'#0'GLDPNG ver' + +' 3.4q'#133#164#225#0#0#0#8'tpNGGLD3'#0#0#0#0'J'#128')'#31#0#0#0#4'gAMA'#0#0 + +#177#143#11#252'a'#5#0#0#1'(IDATx'#156'c`'#160'''X~'#232#217#127#167#178'#X1' + +'H'#142'*'#6'_~'#248#249'?'#8#128#232#189#23#223#128#13#158#184#233'>e'#22 + +#129'4'#22#204#190#6'6'#8'd('#186#225#213#139'o'#130#229'S&_'#2'[B'#178#5'0' + +#141'0'#23'b3'#28'&'#15'RK'#150#5' '#131#144#131#2#29'#'#251#130'd'#11'\+' + +#142#194'-'#0#185#30'['#28' '#251#132','#31#128','#1'i'#134'YP^>'#137'"L0' + +#136'@'#138#136#5' '#181#207#159'?'#134'c'#16#127#253#134#237#8'K'#176#5#17 + +#204#2'CCc'#188#24#217#2'{{;'#236#22#224#10'"'#170#249#0'W'#16#193'pee'#227 + +#255#170#170'*'#156#184#162#162#3'#'#14#136#10#162#251#247'o'#255#159#182#245 + +'9Q4'#204'P'#24'F'#137'dPR'#196#22'D '#205#196'b'#12'Wc'#3#200'e'#18'!'#31#0 + +'M'#2'ct'#31#16#157'7'#8#249#0#217#2#162'}'#128'n'#1'9q@'#150#15#208']Kv'#28 + +#224#242#1#204#2#154#249#0#31#222'~'#230#29#24'S='#14'@'#134'"'#211'dY@*&' + +#201#2#16'x'#255#254'-'#195#186'u'#219#255#195'0rN'#197#133'I'#178#128#26#0#0 + +#242#176#9'l'#161#206':'#16#0#0#0#0'IEND'#174'B`'#130 +]); diff --git a/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.pas b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.pas new file mode 100644 index 000000000..b114ca831 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimectrls.pas @@ -0,0 +1,22 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit ZVDateTimeCtrls; + +interface + +uses + ZVDateTimePicker, DBZVDateTimePicker, ZVDateTimePickerPropEdit, + ZVDateTimeControlsReg, LazarusPackageIntf; + +implementation + +procedure Register; +begin + RegisterUnit('ZVDateTimeControlsReg', @ZVDateTimeControlsReg.Register); +end; + +initialization + RegisterPackage('ZVDateTimeCtrls', @Register); +end. diff --git a/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepicker.pas b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepicker.pas new file mode 100644 index 000000000..f9accfed5 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepicker.pas @@ -0,0 +1,3279 @@ +{ +TZVDateTimePicker control for Lazarus +- - - - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + +Last change: September 2012 + + This unit is part of ZVDateTimeCtrls package for Lazarus. + + Delphi's Visual Component Library (VCL) has a control named TDateTimePicker, +which I find very useful for editing dates. Lazarus Component Library (LCL), +however, does not have this control, because VCL wraps native Windows control +and it seems that such control does not exist on other platforms. Given that +LCL is designed to be platform independent, it could not use native Win control. + Instead, for editing dates LCL has a control named TDateEdit, but I prefer +the VCL's TDateTimePicker. + Therefore, I tried to create a custom control which would resemble VCL's +TDateTimePicker as much as possible, but not to rely on native Windows control. + + This TZVDateTimePicker control does not use native Win control. It has been +tested on Windows with win32/64 and qt widgetsets, as well as on Linux with +qt and gtk2 widgetsets. + +----------------------------------------------------------- +LICENCE +- - - - + Modified LGPL -- see the file COPYING.modifiedLGPL. + +----------------------------------------------------------- +NO WARRANTY +- - - - - - + There is no warranty whatsoever. + +----------------------------------------------------------- +BEST REGARDS TO LAZARUS COMMUNITY! +- - - - - - - - - - - - - - - - - - + I do hope this control will be useful. +} +unit ZVDateTimePicker; + +{$mode objfpc}{$H+} + +interface + +uses + {$ifdef unix} + clocale, // needed to initialize default local settings on Linux. + {$endif} + Classes, SysUtils, LCLProc, Controls, LCLType, Graphics, Math, StdCtrls, + Buttons, ExtCtrls, Forms, Calendar, ComCtrls, Types, LMessages + {$ifdef LCLGtk2}, LCLVersion{$endif} + ; + +const + { We will deal with the NullDate value the special way. It will be especially + useful for dealing with null values from database. } + NullDate = TDateTime(Math.MaxDouble); + + { The biggest date a user can enter. } + TheBiggestDate = TDateTime(2958465.0); // 31. dec. 9999. + + { The smallest date a user can enter. + Note: + TCalendar does not accept smaller dates then 14. sep. 1752 on Windows OS + (see the implementation of TCustomCalendar.SetDateTime). + In Delphi help it is documented that Windows controls act weird with dates + older than 24. sep. 1752. Actually, TCalendar control has problems to show + dates before 1. okt. 1752. (try putting one calendar on the form, run the + application and see what september 1752. looks like). + Let's behave uniformely as much as + possible -- we won't allow dates before 1. okt. 1752. on any OS (who cares + about those). + So, this will be the down limit: } + TheSmallestDate = TDateTime(-53780.0); // 1. okt. 1752. + +type + TYMD = record + Year, Month, Day: Word; + end; + + THMSMs = record + Hour, Minute, Second, MiliSec: Word; + end; + + { Used by DateDisplayOrder property to determine the order to display date + parts -- d-m-y, m-d-y or y-m-d. + When ddoTryDefault is set, the actual order is determined from + ShortDateFormat global variable -- see coments above AdjustDateDisplayOrder + procedure } + TDateDisplayOrder = (ddoDMY, ddoMDY, ddoYMD, ddoTryDefault); + + TDateTextPart = (dtpDay, dtpMonth, dtpYear, dtpTime); + + TTimeDisplay = (tdHM, // hour and minute + tdHMS, // hour, minute and second + tdHMSMs // hour, minute, second and milisecond + ); + + TTimeFormat = (tf12, // 12 hours format, with am/pm string + tf24 // 24 hours format + ); + + { TDateTimeKind determines if we should display date, time or both: } + TDateTimeKind = (dtkDate, dtkTime, dtkDateTime); + + TTimeTextPart = (ttpHour, ttpMinute, ttpSecond, ttpMiliSec, ttpAMPM); + + TArrowShape = (asClassicSmaller, asClassicLarger, asModernSmaller, + asModernLarger, asYetAnotherShape); + + TDTDateMode = (dmComboBox, dmUpDown, dmNone); + + { TCustomZVDateTimePicker } + + TCustomZVDateTimePicker = class(TCustomControl) + private + FCenturyFrom, FEffectiveCenturyFrom: Word; + FDateDisplayOrder: TDateDisplayOrder; + FKind: TDateTimeKind; + FLeadingZeros: Boolean; + FNullInputAllowed: Boolean; + FDateTime: TDateTime; + FDateSeparator: String; + FReadOnly: Boolean; + FMaxDate, FMinDate: TDate; + FTextForNullDate: String; + FTimeSeparator: String; + FTimeDisplay: TTimeDisplay; + FTimeFormat: TTimeFormat; + FTrailingSeparator: Boolean; + FUseDefaultSeparators: Boolean; + FUserChangedText: Boolean; + FTextPart: array[1..3] of String; + FTimeText: array[TTimeTextPart] of String; + FUserChanging: Integer; + FDigitWidth: Integer; + FTextHeight: Integer; + FSeparatorWidth: Integer; + FSepNoSpaceWidth: Integer; + FTimeSeparatorWidth: Integer; + FSelectedTextPart: 1..8; + FRecalculatingTextSizesNeeded: Boolean; + FJumpMinMax: Boolean; + FAMPMWidth: Integer; + FDateWidth: Integer; + FTimeWidth: Integer; + FTextWidth: Integer; + FArrowShape: TArrowShape; + FDateMode: TDTDateMode; + FTextEnabled: Boolean; + FCheckBox: TCheckBox; + FUpDown: TCustomUpDown; + FOnChange: TNotifyEvent; + FOnCheckBoxChange: TNotifyEvent; + FOnDropDown: TNotifyEvent; + FOnCloseUp: TNotifyEvent; + FEffectiveDateDisplayOrder: TDateDisplayOrder; + + FArrowButton: TCustomSpeedButton; + FCalendarForm: TCustomForm; + FDoNotArrangeControls: Boolean; + FConfirmedDateTime: TDateTime; + FNoEditingDone: Integer; + FAllowDroppingCalendar: Boolean; + + function AreSeparatorsStored: Boolean; + function GetChecked: Boolean; + function GetDate: TDate; + function GetDateTime: TDateTime; + function GetShowCheckBox: Boolean; + function GetTime: TTime; + procedure SetArrowShape(const AValue: TArrowShape); + procedure SetCenturyFrom(const AValue: Word); + procedure SetChecked(const AValue: Boolean); + procedure CheckTextEnabled; + procedure SetDateDisplayOrder(const AValue: TDateDisplayOrder); + procedure SetDateMode(const AValue: TDTDateMode); + procedure SetKind(const AValue: TDateTimeKind); + procedure SetLeadingZeros(const AValue: Boolean); + procedure SetNullInputAllowed(const AValue: Boolean); + procedure SetDate(const AValue: TDate); + procedure SetDateTime(const AValue: TDateTime); + procedure SetDateSeparator(const AValue: String); + procedure SetMaxDate(const AValue: TDate); + procedure SetMinDate(const AValue: TDate); + procedure SetReadOnly(const AValue: Boolean); + procedure SetShowCheckBox(const AValue: Boolean); + procedure SetTextForNullDate(const AValue: String); + procedure SetTime(const AValue: TTime); + procedure SetTimeSeparator(const AValue: String); + procedure SetTimeDisplay(const AValue: TTimeDisplay); + procedure SetTimeFormat(const AValue: TTimeFormat); + procedure SetTrailingSeparator(const AValue: Boolean); + procedure SetUseDefaultSeparators(const AValue: Boolean); + + function GetHour: Word; + function GetMiliSec: Word; + function GetMinute: Word; + function GetSecond: Word; + procedure RecalculateTextSizesIfNeeded; + function GetDay: Word; + function GetMonth: Word; + function GetYear: Word; + function GetHMSMs(const NowIfNull: Boolean = False): THMSMs; + function GetYYYYMMDD(const TodayIfNull: Boolean = False): TYMD; + procedure SetHour(const AValue: Word); + procedure SetMiliSec(const AValue: Word); + procedure SetMinute(const AValue: Word); + procedure SetSecond(const AValue: Word); + procedure SetSeparators(const DateSep, TimeSep: String); + procedure SetDay(const AValue: Word); + procedure SetMonth(const AValue: Word); + procedure SetYear(const AValue: Word); + procedure SetYYYYMMDD(const AValue: TYMD); + procedure SetHMSMs(const AValue: THMSMs); + procedure UpdateIfUserChangedText; + function GetSelectedText: String; + procedure AdjustEffectiveCenturyFrom; + procedure AdjustEffectiveDateDisplayOrder; + procedure SelectDateTextPart(const DateTextPart: TDateTextPart); + procedure SelectTimeTextPart(const TimeTextPart: TTimeTextPart); + procedure DestroyCalendarForm; + procedure DropDownCalendarForm; + procedure UpdateShowArrowButton(NewDateMode: TDTDateMode; + NewKind: TDateTimeKind); + procedure DestroyUpDown; + procedure DestroyArrowBtn; + procedure ArrowMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure UpDownClick(Sender: TObject; Button: TUDBtnType); + procedure CheckBoxChange(Sender: TObject); + procedure SetFocusIfPossible; + + protected + procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS; + + class function GetControlClassDefaultSize: TSize; override; + + procedure ConfirmChanges; virtual; + procedure UndoChanges; virtual; + + function GetCurrentDateTextPart: TDateTextPart; + function GetCurrentTimeTextPart: TTimeTextPart; + procedure FontChanged(Sender: TObject); override; + function GetTextOrigin: TPoint; + procedure KeyDown(var Key: Word; Shift: TShiftState); override; + procedure KeyPress(var Key: char); override; + procedure SelectTextPartUnderMouse(XMouse: Integer); + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override; + procedure UpdateDate; virtual; + procedure DoEnter; override; + procedure DoExit; override; + procedure Click; override; + procedure DblClick; override; + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; + procedure KeyUp(var Key: Word; Shift: TShiftState); override; + procedure UTF8KeyPress(var UTF8Key: TUTF8Char); override; + procedure CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); override; + + procedure IncreaseCurrentTextPart; + procedure DecreaseCurrentTextPart; + procedure IncreaseMonth; + procedure IncreaseYear; + procedure IncreaseDay; + procedure DecreaseMonth; + procedure DecreaseYear; + procedure DecreaseDay; + procedure IncreaseHour; + procedure IncreaseMinute; + procedure IncreaseSecond; + procedure IncreaseMiliSec; + procedure DecreaseHour; + procedure DecreaseMinute; + procedure DecreaseSecond; + procedure DecreaseMiliSec; + procedure ChangeAMPM; + + procedure SelectDay; + procedure SelectMonth; + procedure SelectYear; + procedure SelectHour; + procedure SelectMinute; + procedure SelectSecond; + procedure SelectMiliSec; + procedure SelectAMPM; + + procedure SetEnabled(Value: Boolean); override; + procedure SetAutoSize(Value: Boolean); override; + procedure CreateWnd; override; + procedure SetDateTimeJumpMinMax(const AValue: TDateTime); + procedure ArrangeCtrls; virtual; + procedure Change; virtual; + procedure DoDropDown; virtual; + procedure DoCloseUp; virtual; + procedure DrawArrowButtonGlyph; virtual; + + property BorderStyle default bsSingle; + property AutoSize default True; + property TabStop default True; + property ParentColor default False; + property CenturyFrom: Word + read FCenturyFrom write SetCenturyFrom; + property DateDisplayOrder: TDateDisplayOrder + read FDateDisplayOrder write SetDateDisplayOrder default ddoTryDefault; + property MaxDate: TDate + read FMaxDate write SetMaxDate; + property MinDate: TDate + read FMinDate write SetMinDate; + property DateTime: TDateTime read GetDateTime write SetDateTime; + property TrailingSeparator: Boolean + read FTrailingSeparator write SetTrailingSeparator; + property ReadOnly: Boolean read FReadOnly write SetReadOnly default False; + property LeadingZeros: Boolean read FLeadingZeros write SetLeadingZeros; + property TextForNullDate: String + read FTextForNullDate write SetTextForNullDate; + property NullInputAllowed: Boolean + read FNullInputAllowed write SetNullInputAllowed default True; + property OnChange: TNotifyEvent read FOnChange write FOnChange; + property OnCheckBoxChange: TNotifyEvent + read FOnCheckBoxChange write FOnCheckBoxChange; + property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown; + property OnCloseUp: TNotifyEvent read FOnCloseUp write FOnCloseUp; + property ShowCheckBox: Boolean + read GetShowCheckBox write SetShowCheckBox default False; + property Checked: Boolean read GetChecked write SetChecked default True; + property ArrowShape: TArrowShape + read FArrowShape write SetArrowShape default asModernSmaller; + property Kind: TDateTimeKind + read FKind write SetKind; + property DateSeparator: String + read FDateSeparator write SetDateSeparator stored AreSeparatorsStored; + property TimeSeparator: String + read FTimeSeparator write SetTimeSeparator stored AreSeparatorsStored; + property UseDefaultSeparators: Boolean + read FUseDefaultSeparators write SetUseDefaultSeparators; + property TimeFormat: TTimeFormat read FTimeFormat write SetTimeFormat; + property TimeDisplay: TTimeDisplay read FTimeDisplay write SetTimeDisplay; + property Time: TTime read GetTime write SetTime; + property Date: TDate read GetDate write SetDate; + property DateMode: TDTDateMode read FDateMode write SetDateMode; + + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + function DateIsNull: Boolean; + procedure SelectDate; + procedure SelectTime; + + procedure Paint; override; + procedure EditingDone; override; + + published + // + end; + + {TZVDateTimePicker} + + TZVDateTimePicker = class(TCustomZVDateTimePicker) + public + property DateTime; + published + property ArrowShape; + property ShowCheckBox; + property Checked; + property CenturyFrom; + property DateDisplayOrder; + property MaxDate; + property MinDate; + property ReadOnly; + property AutoSize; + property Font; + property ParentFont; + property TabOrder; + property TabStop; + property BorderStyle; + property BorderSpacing; + property Enabled; + property Color; + property ParentColor; + property DateSeparator; + property TrailingSeparator; + property TextForNullDate; + property LeadingZeros; + property ShowHint; + property ParentShowHint; + property Align; + property Anchors; + property Constraints; + property Cursor; + property PopupMenu; + property Visible; + property NullInputAllowed; + property Kind; + property TimeSeparator; + property TimeFormat; + property TimeDisplay; + property DateMode; + property Date; + property Time; + property UseDefaultSeparators; +// events: + property OnChange; + property OnCheckBoxChange; + property OnDropDown; + property OnCloseUp; + property OnChangeBounds; + property OnClick; + property OnContextPopup; + property OnDblClick; + property OnEditingDone; + property OnEnter; + property OnExit; + property OnKeyDown; + property OnKeyPress; + property OnKeyUp; + property OnMouseDown; + property OnMouseEnter; + property OnMouseMove; + property OnMouseUp; + property OnMouseLeave; + property OnResize; + property OnUTF8KeyPress; + end; + +function EqualDateTime(const A, B: TDateTime): Boolean; +function IsNullDate(DT: TDateTime): Boolean; + +implementation + +function NumberOfDaysInMonth(const Month, Year: Word): Word; +begin + Result := 0; + if Month in [1..12] then + Result := MonthDays[IsLeapYear(Year), Month]; +end; + +{ EqualDateTime + -------------- + Returns True when two dates are equal or both are null } +function EqualDateTime(const A, B: TDateTime): Boolean; +begin + if IsNullDate(A) then + Result := IsNullDate(B) + else + Result := (not IsNullDate(B)) and (A = B); +end; + +function IsNullDate(DT: TDateTime): Boolean; +begin + Result := IsNan(DT) or IsInfinite(DT) or + (DT > SysUtils.MaxDateTime) or (DT < SysUtils.MinDateTime); +end; + +procedure Exchange(var W1, W2: Word); +var + W: Word; +begin + W := W1; + W1 := W2; + W2 := W; +end; + +{ TCustomZVDateTimePicker } + +procedure TCustomZVDateTimePicker.SetChecked(const AValue: Boolean); +begin + if Assigned(FCheckBox) then + FCheckBox.Checked := AValue; + + CheckTextEnabled; + Invalidate; +end; + +type + + { TDTCalendarForm } + + TDTCalendarForm = class(TForm) + private + DTPicker: TCustomZVDateTimePicker; + Cal: TCalendar; + Shape: TShape; + RememberedCalendarFormOrigin: TPoint; + FClosing: Boolean; + DTPickersParentForm: TCustomForm; + + procedure SetClosingCalendarForm; + procedure AdjustCalendarFormSize; + procedure AdjustCalendarFormScreenPosition; + procedure CloseCalendarForm(const AndSetTheDate: Boolean = False); + + procedure CalendarKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure CalendarResize(Sender: TObject); + procedure CalendarMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure VisibleOfParentChanged(Sender: TObject); + procedure Notification(AComponent: TComponent; Operation: TOperation); override; + + protected + procedure Deactivate; override; + procedure DoShow; override; + procedure DoClose(var CloseAction: TCloseAction); override; + + public + constructor CreateNewDTCalendarForm(AOwner: TComponent; + ADTPicker: TCustomZVDateTimePicker); + destructor Destroy; override; + published + end; + +{ TDTCalendarForm } + +procedure TDTCalendarForm.SetClosingCalendarForm; +begin + if not FClosing then begin + FClosing := True; + + if Assigned(DTPicker) and (DTPicker.FCalendarForm = Self) then + DTPicker.FCalendarForm := nil; + + end; +end; + +procedure TDTCalendarForm.AdjustCalendarFormSize; +begin + if not FClosing then begin + ClientWidth := Cal.Width + 2; + ClientHeight := Cal.Height + 2; + + Shape.SetBounds(0, 0, ClientWidth, ClientHeight); + + AdjustCalendarFormScreenPosition; + + end; +end; + +procedure TDTCalendarForm.AdjustCalendarFormScreenPosition; +var + R: TRect; + P: TPoint; + H, W: Integer; +begin + H := Height; + W := Width; + + P := DTPicker.ControlToScreen(Point(0, DTPicker.Height)); + + R := Screen.MonitorFromWindow(DTPicker.Handle).WorkareaRect; + + if P.y > R.Bottom - H then + P.y := P.y - H - DTPicker.Height; + + if P.y < R.Top then + P.y := R.Top; + + if P.x > R.Right - W then + P.x := R.Right - W; + + if P.x < R.Left then + P.x := R.Left; + + if (P.x <> RememberedCalendarFormOrigin.x) + or (P.y <> RememberedCalendarFormOrigin.y) then begin + SetBounds(P.x, P.y, W, H); + RememberedCalendarFormOrigin := P; + end; + +end; + +procedure TDTCalendarForm.CloseCalendarForm(const AndSetTheDate: Boolean); +begin + if not FClosing then begin + SetClosingCalendarForm; + + if Assigned(DTPicker) and DTPicker.IsVisible then begin + + if AndSetTheDate then begin + Inc(DTPicker.FUserChanging); + try + if DTPicker.DateIsNull then begin + // we'll set the time to 0.0 (midnight): + DTPicker.SetDateTime(Int(Cal.DateTime)); + end else if not EqualDateTime(Int(DTPicker.DateTime), + Int(Cal.DateTime)) then begin + // we'll change the date, but keep the time: + DTPicker.SetDateTime(ComposeDateTime(Cal.DateTime, DTPicker.DateTime)); + end; + finally + Dec(DTPicker.FUserChanging); + end; + end; + + if Screen.ActiveCustomForm = Self then + DTPicker.SetFocusIfPossible; + + Visible := False; + + Close; + DTPicker.DoCloseUp; + + end else + Close; + + end; + +end; + +procedure TDTCalendarForm.CalendarKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + case Key of + VK_ESCAPE: + CloseCalendarForm; + + VK_RETURN, VK_SPACE: + CloseCalendarForm(True); + + end; +end; + +procedure TDTCalendarForm.CalendarResize(Sender: TObject); +begin + AdjustCalendarFormSize; +end; + +procedure TDTCalendarForm.CalendarMouseUp(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + if Cal.HitTest(Point(X, Y)) in [cpDate, cpNoWhere] then + CloseCalendarForm(True); + +end; + +{ This procedure is added to list of "visible change handlers" of DTPicker's + parent form, so that hiding of DTPicker's parent form does not leave the + calendar form visible. } +procedure TDTCalendarForm.VisibleOfParentChanged(Sender: TObject); +begin + SetClosingCalendarForm; + Release; +end; + +procedure TDTCalendarForm.Notification(AComponent: TComponent; + Operation: TOperation); +begin + inherited Notification(AComponent, Operation); + + if (AComponent = DTPickersParentForm) and (Operation = opRemove) then + DTPickersParentForm := nil; + +end; + +procedure TDTCalendarForm.Deactivate; +begin + inherited Deactivate; + + CloseCalendarForm; +end; + +procedure TDTCalendarForm.DoShow; +begin + if not FClosing then begin + inherited DoShow; + + AdjustCalendarFormSize; + DTPicker.DoDropDown; // calls OnDropDown event handler + end; +end; + +procedure TDTCalendarForm.DoClose(var CloseAction: TCloseAction); +begin + SetClosingCalendarForm; + CloseAction := caFree; + + inherited DoClose(CloseAction); +end; + +constructor TDTCalendarForm.CreateNewDTCalendarForm(AOwner: TComponent; + ADTPicker: TCustomZVDateTimePicker); +var + P: TPoint; +begin + inherited CreateNew(AOwner); + + ADTPicker.FAllowDroppingCalendar := False; + FClosing := False; + + DTPicker := ADTPicker; + DTPickersParentForm := GetParentForm(DTPicker); + if Assigned(DTPickersParentForm) then begin + DTPickersParentForm.AddHandlerOnVisibleChanged(@VisibleOfParentChanged); + DTPickersParentForm.FreeNotification(Self); + end; + + P := Point(0, 0); + + Cal := TCalendar.Create(nil); + Cal.AutoSize := True; + Cal.GetPreferredSize(P.x, P.y); + + Cal.Align := alNone; + + Cal.SetBounds(1, 1, P.x, P.y); + Cal.TabStop := True; + + PopupMode := pmAuto; + + SetBounds(-8000, -8000, P.x + 2, P.y + 2); + RememberedCalendarFormOrigin := Point(-8000, -8000); + + ShowInTaskBar := stNever; + BorderStyle := bsNone; + + Shape := TShape.Create(nil); + Shape.Brush.Style := bsClear; + + if DTPicker.DateIsNull then + Cal.DateTime := Max(DTPicker.MinDate, Min(SysUtils.Date, DTPicker.MaxDate)) + + else if DTPicker.DateTime < DTPicker.MinDate then // These "out of bounds" values + Cal.DateTime := DTPicker.MinDate // can happen when DateTime was set with + else if DTPicker.DateTime > DTPicker.MaxDate then // "SetDateTimeJumpMinMax" protected + Cal.DateTime := DTPicker.MaxDate // procedure (used in TDBZVDateTimePicker control). + + else + Cal.DateTime := DTPicker.DateTime; + + Cal.Parent := Self; + Shape.Parent := Self; + + Cal.OnResize := @CalendarResize; + Cal.OnMouseUp := @CalendarMouseUp; + Cal.OnKeyDown := @CalendarKeyDown; + +end; + +destructor TDTCalendarForm.Destroy; +begin + SetClosingCalendarForm; + if Assigned(DTPickersParentForm) then + DTPickersParentForm.RemoveAllHandlersOfObject(Self); + + if Assigned(Cal) then begin + Cal.OnResize := nil; + Cal.OnMouseUp := nil; + Cal.OnKeyDown := nil; + Cal.Free; + Cal := nil; + end; + FreeAndNil(Shape); + + if Assigned(DTPicker) then begin + if (Screen.ActiveControl = DTPicker) then + DTPicker.Invalidate; + + if DTPicker.FCalendarForm = nil then + DTPicker.FAllowDroppingCalendar := True; + + end; + + inherited Destroy; +end; + +procedure TCustomZVDateTimePicker.CheckTextEnabled; +begin + FTextEnabled := Self.Enabled and GetChecked; + + if Assigned(FArrowButton) then + FArrowButton.Enabled := FTextEnabled; + + if Assigned(FUpDown) then + FUpDown.Enabled := FTextEnabled; + + if Assigned(FCheckBox) then + FCheckBox.Enabled := Self.Enabled; +end; + +procedure TCustomZVDateTimePicker.SetDateDisplayOrder(const AValue: TDateDisplayOrder); +var + PreviousEffectiveDDO: TDateDisplayOrder; +begin + if FDateDisplayOrder <> AValue then begin + PreviousEffectiveDDO := FEffectiveDateDisplayOrder; + FDateDisplayOrder := AValue; + AdjustEffectiveDateDisplayOrder; + if FEffectiveDateDisplayOrder <> PreviousEffectiveDDO then + UpdateDate; + end; +end; + +procedure TCustomZVDateTimePicker.SetDateMode(const AValue: TDTDateMode); +begin + UpdateShowArrowButton(AValue, Kind); + FDateMode := AValue; +end; + +procedure TCustomZVDateTimePicker.SetKind(const AValue: TDateTimeKind); +begin + if FKind <> AValue then begin + UpdateShowArrowButton(FDateMode, AValue); + + FKind := AValue; + FRecalculatingTextSizesNeeded := True; + + UpdateDate; + end; +end; + +procedure TCustomZVDateTimePicker.SetLeadingZeros(const AValue: Boolean); +begin + if FLeadingZeros = AValue then Exit; + + FLeadingZeros := AValue; + UpdateDate; +end; + +procedure TCustomZVDateTimePicker.SetNullInputAllowed(const AValue: Boolean); +begin + FNullInputAllowed := AValue; +end; + +procedure TCustomZVDateTimePicker.SetDate(const AValue: TDate); +begin + if IsNullDate(AValue) then + DateTime := NullDate + else if DateIsNull then + DateTime := Int(AValue) + else + DateTime := ComposeDateTime(AValue, FDateTime); +end; + +procedure TCustomZVDateTimePicker.SetDateTime(const AValue: TDateTime); +begin + if not EqualDateTime(AValue, FDateTime) then begin + if IsNullDate(AValue) then + FDateTime := NullDate + else + FDateTime := AValue; + end; + UpdateDate; +end; + +procedure TCustomZVDateTimePicker.SetDateSeparator(const AValue: String); +begin + SetSeparators(AValue, FTimeSeparator); +end; + +procedure TCustomZVDateTimePicker.SetMaxDate(const AValue: TDate); +begin + if not IsNullDate(AValue) then begin + + if AValue > TheBiggestDate then + FMaxDate := TheBiggestDate + else if AValue <= FMinDate then + FMaxDate := FMinDate + else + FMaxDate := Int(AValue); + + if not DateIsNull then + if FMaxDate < GetDate then + SetDate(FMaxDate); + + AdjustEffectiveCenturyFrom; + end; +end; + +procedure TCustomZVDateTimePicker.SetMinDate(const AValue: TDate); +begin + if not IsNullDate(AValue) then begin + + if AValue < TheSmallestDate then + FMinDate := TheSmallestDate + else if AValue >= FMaxDate then + FMinDate := FMaxDate + else + FMinDate := Int(AValue); + + if not DateIsNull then + if FMinDate > GetDate then + SetDate(FMinDate); + + AdjustEffectiveCenturyFrom; + end; +end; + +procedure TCustomZVDateTimePicker.SetReadOnly(const AValue: Boolean); +begin + if FReadOnly <> AValue then begin + if AValue then + ConfirmChanges; + + FReadOnly := AValue; + end; +end; + +type + TDTCheckBox = class(TCheckBox) + protected + procedure CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); override; + end; + +procedure TDTCheckBox.CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); +begin + inherited CalculatePreferredSize(PreferredWidth, PreferredHeight, + WithThemeSpace); + + PreferredHeight := 1; +end; + +procedure TCustomZVDateTimePicker.SetShowCheckBox(const AValue: Boolean); +begin + if GetShowCheckBox <> AValue then begin + DisableAlign; + try + if AValue then begin + FCheckBox := TDTCheckBox.Create(Self); + + {$IFNDEF WINDOWS} + { On Windows, the following line seems to not have any effect, but I + enclosed it in IFNDEF anyway. } + FCheckBox.Color := clBtnFace; { This line is here because of CheckBox's + strange behavior in Linux -- when parent's colour is white, which is + the default in our case (actually, our default is clWindow, but it's + usually white) and when the check box is on a form shown modally, if + we close the form and then show it again, the check box refuses to + paint it's "checker" shape. + + I spent a lot of time trying to solve this and this is the best I + came up with -- setting the check box's colour to clBtnFace seems to + be a workaround. + + Nice thing is that it seems not to really effect neither the checker's + colour on the screen, nor the colour of check box's "box", so we didn't + actually spoil the check box's default appearence on the screen. } + {$ENDIF} + + FCheckBox.ControlStyle := FCheckBox.ControlStyle + + [csNoFocus, csNoDesignSelectable]; + FCheckBox.AllowGrayed := False; + FCheckBox.TabStop := False; + + FCheckBox.Checked := True; + FCheckBox.Enabled := Self.Enabled; + + FCheckBox.Parent := Self; + + end else begin + FCheckBox.OnChange := nil; + FreeAndNil(FCheckBox); + + end; + ArrangeCtrls; + + finally + EnableAlign; + end; + end; +end; + +procedure TCustomZVDateTimePicker.SetTextForNullDate(const AValue: String); +begin + if FTextForNullDate = AValue then + Exit; + + FTextForNullDate := AValue; + if DateIsNull then + Invalidate; +end; + +procedure TCustomZVDateTimePicker.SetTime(const AValue: TTime); +begin + if IsNullDate(AValue) then + DateTime := NullDate + else if DateIsNull then + DateTime := ComposeDateTime(Max(Min(SysUtils.Date, MaxDate), MinDate), AValue) + else + DateTime := ComposeDateTime(FDateTime, AValue); +end; + +procedure TCustomZVDateTimePicker.SetTimeSeparator(const AValue: String); +begin + SetSeparators(FDateSeparator, AValue); +end; + +procedure TCustomZVDateTimePicker.SetTimeDisplay(const AValue: TTimeDisplay); +begin + if FTimeDisplay <> AValue then begin + FTimeDisplay:=AValue; + FRecalculatingTextSizesNeeded := True; + + UpdateDate; + end; +end; + +procedure TCustomZVDateTimePicker.SetTimeFormat(const AValue: TTimeFormat); +begin + if FTimeFormat <> AValue then begin + FTimeFormat := AValue; + FRecalculatingTextSizesNeeded := True; + + UpdateDate; + end; +end; + +procedure TCustomZVDateTimePicker.SetTrailingSeparator(const AValue: Boolean); +begin + if FTrailingSeparator <> AValue then begin + FTrailingSeparator := AValue; + FRecalculatingTextSizesNeeded := True; + UpdateIfUserChangedText; + Invalidate; + end; +end; + +procedure TCustomZVDateTimePicker.SetUseDefaultSeparators(const AValue: Boolean); +begin + if FUseDefaultSeparators <> AValue then begin + if AValue then begin + SetSeparators(DefaultFormatSettings.DateSeparator, + DefaultFormatSettings.TimeSeparator); + // Note that here, in SetSeparators procedure, + // the field FUseDefaultSeparators is set to False. + end; + // Therefore, the following line must NOT be moved above. + FUseDefaultSeparators := AValue; + end; +end; + +function TCustomZVDateTimePicker.GetHour: Word; +begin + Result := GetHMSMs.Hour; +end; + +function TCustomZVDateTimePicker.GetMiliSec: Word; +begin + Result := GetHMSMs.MiliSec; +end; + +function TCustomZVDateTimePicker.GetMinute: Word; +begin + Result := GetHMSMs.Minute; +end; + +function TCustomZVDateTimePicker.GetSecond: Word; +begin + Result := GetHMSMs.Second; +end; + +{ RecalculateTextSizesIfNeeded + -------------------------------- + In this procedure we measure text and store the values in the following + fields: FDateWidth, FTimeWidth, FTextWidth, FTextHeigth, FDigitWidth, + FSeparatorWidth, FTimeSeparatorWidth, FSepNoSpaceWidth. These fields are used + in calculating our preffered size and when painting. + The procedure is called internally when needed (when properties which + influence the appearence change). } +procedure TCustomZVDateTimePicker.RecalculateTextSizesIfNeeded; +var + C: Char; + N: Integer; + S: String; +begin + if FRecalculatingTextSizesNeeded then begin + FRecalculatingTextSizesNeeded := False; + + FDigitWidth := 0; + for C := '0' to '9' do begin + N := Canvas.GetTextWidth(C); + if N > FDigitWidth then + FDigitWidth := N; + end; + + if FKind in [dtkDate, dtkDateTime] then begin + + FSeparatorWidth := Canvas.GetTextWidth(FDateSeparator); + FDateWidth := 8 * FDigitWidth + 2 * FSeparatorWidth; + + if FTrailingSeparator then begin + FSepNoSpaceWidth := Canvas.GetTextWidth(TrimRight(FDateSeparator)); + Inc(FDateWidth, FSepNoSpaceWidth); + end else + FSepNoSpaceWidth := 0; + + S := FDateSeparator; + end else begin + if FSelectedTextPart < 4 then + FSelectedTextPart := 4; + + S := ''; + FSeparatorWidth := 0; + FSepNoSpaceWidth := 0; + FDateWidth := 0; + end; + + FAMPMWidth := 0; + if FKind in [dtkTime, dtkDateTime] then begin + S := S + FTimeSeparator; + + FTimeSeparatorWidth := Canvas.GetTextWidth(FTimeSeparator); + + case FTimeDisplay of + tdHM: + FTimeWidth := 4 * FDigitWidth + FTimeSeparatorWidth; + tdHMS: + FTimeWidth := 6 * FDigitWidth + 2 * FTimeSeparatorWidth; + tdHMSMs: + FTimeWidth := 9 * FDigitWidth + 3 * FTimeSeparatorWidth; + end; + + if FTimeFormat = tf12 then begin + S := S + 'APM'; + FAMPMWidth := Max(Canvas.TextWidth('AM'), Canvas.TextWidth('PM')); + FTimeWidth := FTimeWidth + FDigitWidth + FAMPMWidth; + end; + + if Ord(FTimeDisplay) + 5 < FSelectedTextPart then + if (FSelectedTextPart < 8) or (FTimeFormat = tf24) then + FSelectedTextPart := 4; + + end else begin + if FSelectedTextPart > 3 then + FSelectedTextPart := 1; + + FTimeSeparatorWidth := 0; + FTimeWidth := 0; + end; + + if FKind = dtkDateTime then + FTextWidth := FDateWidth + FTimeWidth + 2 * FDigitWidth + else + FTextWidth := FDateWidth + FTimeWidth; + + FTextHeight := Canvas.GetTextHeight('0123456789' + S); + + end; +end; + +function TCustomZVDateTimePicker.GetDay: Word; +begin + Result := GetYYYYMMDD.Day; +end; + +function TCustomZVDateTimePicker.GetMonth: Word; +begin + Result := GetYYYYMMDD.Month; +end; + +function TCustomZVDateTimePicker.GetYear: Word; +begin + Result := GetYYYYMMDD.Year; +end; + +function TCustomZVDateTimePicker.GetHMSMs(const NowIfNull: Boolean): THMSMs; +begin + if DateIsNull then begin + if NowIfNull then + DecodeTime(SysUtils.Time, Result.Hour, Result.Minute, Result.Second, Result.MiliSec) + else + with Result do begin + Hour := 0; + Minute := 0; + Second := 0; + MiliSec := 0; + end; + end else + DecodeTime(FDateTime, Result.Hour, Result.Minute, Result.Second, Result.MiliSec); +end; + +function TCustomZVDateTimePicker.GetYYYYMMDD(const TodayIfNull: Boolean): TYMD; +begin + if DateIsNull then begin + if TodayIfNull then + DecodeDate(SysUtils.Date, Result.Year, Result.Month, Result.Day) + else + with Result do begin + Day := 0; + Month := 0; + Year := 0; + end; + end else + DecodeDate(FDateTime, Result.Year, Result.Month, Result.Day); +end; + +procedure TCustomZVDateTimePicker.SetHour(const AValue: Word); +var + HMSMs: THMSMs; +begin + SelectHour; + + HMSMs := GetHMSMs(True); + HMSMs.Hour := AValue; + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.SetMiliSec(const AValue: Word); +var + HMSMs: THMSMs; +begin + SelectMiliSec; + + HMSMs := GetHMSMs(True); + HMSMs.MiliSec := AValue; + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.SetMinute(const AValue: Word); +var + HMSMs: THMSMs; +begin + SelectMinute; + + HMSMs := GetHMSMs(True); + HMSMs.Minute := AValue; + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.SetSecond(const AValue: Word); +var + HMSMs: THMSMs; +begin + SelectSecond; + + HMSMs := GetHMSMs(True); + HMSMs.Second := AValue; + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.SetSeparators(const DateSep, TimeSep: String); +var + SeparatorsChanged: Boolean; +begin + FUseDefaultSeparators := False; + SeparatorsChanged := False; + + if FDateSeparator <> DateSep then begin + FDateSeparator := DateSep; + SeparatorsChanged := True; + end; + + if FTimeSeparator <> TimeSep then begin + FTimeSeparator := TimeSep; + SeparatorsChanged := True; + end; + + if SeparatorsChanged then begin + FRecalculatingTextSizesNeeded := True; + Invalidate; + end; + +end; + +procedure TCustomZVDateTimePicker.SetDay(const AValue: Word); +var + YMD: TYMD; +begin + SelectDay; + YMD := GetYYYYMMDD(True); + + YMD.Day := AValue; + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.SetMonth(const AValue: Word); +var + YMD: TYMD; + N: Word; +begin + SelectMonth; + YMD := GetYYYYMMDD(True); + + YMD.Month := AValue; + + N := NumberOfDaysInMonth(YMD.Month, YMD.Year); + if YMD.Day > N then + YMD.Day := N; + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.SetYear(const AValue: Word); +var + YMD: TYMD; +begin + SelectYear; + + YMD := GetYYYYMMDD(True); + YMD.Year := AValue; + if (YMD.Month = 2) and (YMD.Day > 28) and (not IsLeapYear(YMD.Year)) then + YMD.Day := 28; + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.SetYYYYMMDD(const AValue: TYMD); +var + D: TDateTime; +begin + if TryEncodeDate(AValue.Year, AValue.Month, AValue.Day, D) then + SetDate(D) + else + UpdateDate; +end; + +procedure TCustomZVDateTimePicker.SetHMSMs(const AValue: THMSMs); +var + T: TDateTime; +begin + if TryEncodeTime(AValue.Hour, AValue.Minute, + AValue.Second, AValue.MiliSec, T) then + SetTime(T) + else + UpdateDate; +end; + +procedure TCustomZVDateTimePicker.UpdateIfUserChangedText; +var + W: Word; + S: String; +begin + if FUserChangedText then begin + Inc(FUserChanging); + try + FUserChangedText := False; + S := Trim(GetSelectedText); + if FSelectedTextPart = 8 then begin + S := UTF8UpperCase(UTF8Copy(S, 1, 1)); + W := GetHour; + if S = 'A' then begin + if W >= 12 then + Dec(W, 12); + end else begin + if W < 12 then + Inc(W, 12); + end; + SetHour(W); + FSelectedTextPart := 8; + end else begin + + W := StrToInt(S); + case GetCurrentDateTextPart of + dtpYear: + begin + if Length(S) <= 2 then begin + // If user entered the year in two digit format (or even only + // one digit), we will set the year according to the CenturyFrom + // property (We actually use FEffectiveCenturyFrom field, which + // is adjusted to take care of MinDate and MaxDate properties, + // besides CenturyFrom). + if W >= (FEffectiveCenturyFrom mod 100) then + W := W + 100 * (FEffectiveCenturyFrom div 100) + else + W := W + 100 * (FEffectiveCenturyFrom div 100 + 1); + + end; + SetYear(W); + end; + + dtpDay: + SetDay(W); + + dtpMonth: + SetMonth(W); + else + case GetCurrentTimeTextPart of + ttpHour: + begin + if (FTimeFormat = tf12) then begin + if GetHour < 12 then begin + if W = 12 then + SetHour(0) + else + SetHour(W); + end else begin + if W = 12 then + SetHour(W) + else + SetHour(W + 12); + end; + end else + SetHour(W); + end; + ttpMinute: + SetMinute(W); + ttpSecond: + SetSecond(W); + ttpMiliSec: + SetMiliSec(W); + end; + end; + + end; + finally + Dec(FUserChanging); + end; + end; +end; + +function TCustomZVDateTimePicker.GetSelectedText: String; +begin + if FSelectedTextPart <= 3 then + Result := FTextPart[FSelectedTextPart] + else + Result := FTimeText[TTimeTextPart(FSelectedTextPart - 4)]; +end; + +procedure TCustomZVDateTimePicker.AdjustEffectiveCenturyFrom; +var + Y1, Y2, M, D: Word; +begin + DecodeDate(FMinDate, Y1, M, D); + + if Y1 > FCenturyFrom then + FEffectiveCenturyFrom := Y1 // If we use CenturyFrom which is set to value + // below MinDate's year, then when user enters two digit year, the + // DateTime would automatically be set to MinDate value, even though + // we perhaps allow same two-digit year in following centuries. It + // would be less user friendly. + // This is therefore better. + + else begin + DecodeDate(FMaxDate, Y2, M, D); + + if Y2 < 100 then + Y2 := 0 + else + Dec(Y2, 99); // -- We should not use CenturyFrom if it is set to value + // greater then MaxDate's year minus 100 years. + // For example: + // if CenturyFrom = 1941 and MaxDate = 31.12.2025, then if user enters + // Year 33, we could not set the year to 2033 anyway, because of MaxDate + // limit. Note that if we just leave CenturyFrom to effectively remain as + // is, then in case of our example the DateTime would be automatically + // reduced to MaxDate value. Setting the year to 1933 is rather expected + // behaviour, so our internal field FEffectiveCenturyFrom should be 1926. + + // Therefore: + if Y2 < FCenturyFrom then + FEffectiveCenturyFrom := Max(Y1, Y2) + else + FEffectiveCenturyFrom := FCenturyFrom; // -- FCenturyFrom has passed all + // our tests, so we'll really use it without any correction. + end; +end; + +{ AdjustEffectiveDateDisplayOrder procedure + ---------------------------------- + If date display order ddoTryDefault is set, then we will decide which + display order to use according to ShortDateFormat global variable. This + procedure tries to achieve that by searching through short date format string, + to see which letter comes first -- d, m or y. When it finds any of these + characters, it assumes that date order should be d-m-y, m-d-y, or y-m-d + respectively. If the search through ShortDateFormat is unsuccessful by any + chance, we try the same with LongDateFormat global variable. If we don't + succeed again, we'll assume y-m-d order. } +procedure TCustomZVDateTimePicker.AdjustEffectiveDateDisplayOrder; +var + S: String; + I: Integer; +begin + if FDateDisplayOrder = ddoTryDefault then begin + S := DefaultFormatSettings.ShortDateFormat; + FEffectiveDateDisplayOrder := ddoTryDefault; + + repeat + + for I := 1 to Length(S) do begin + case upCase(S[I]) of + 'D': begin + FEffectiveDateDisplayOrder := ddoDMY; + Break; + end; + 'M': begin + FEffectiveDateDisplayOrder := ddoMDY; + Break; + end; + 'Y': begin + FEffectiveDateDisplayOrder := ddoYMD; + Break; + end; + end; + end; + + if FEffectiveDateDisplayOrder = ddoTryDefault then begin + { We couldn't decide with ShortDateFormat, let's try with + LongDateFormat now. } + S := DefaultFormatSettings.LongDateFormat; + { But now we must set something to be default. This ensures that the + repeat loop breaks next time. If we don't find anything in + LongDateFormat, we'll leave with y-m-d order. } + FEffectiveDateDisplayOrder := ddoYMD; + + end else + Break; + + until False; + + end else + FEffectiveDateDisplayOrder := FDateDisplayOrder; + +end; + +procedure TCustomZVDateTimePicker.SelectDateTextPart( + const DateTextPart: TDateTextPart); +begin + if FKind in [dtkDate, dtkDateTime] then begin + + case DateTextPart of + dtpDay: + begin + case FEffectiveDateDisplayOrder of + ddoDMY: FSelectedTextPart := 1; + ddoMDY: FSelectedTextPart := 2; + ddoYMD: FSelectedTextPart := 3; + end; + end; + dtpMonth: + begin + if FEffectiveDateDisplayOrder = ddoMDY then + FSelectedTextPart := 1 + else + FSelectedTextPart := 2; + end; + dtpYear: + begin + if FEffectiveDateDisplayOrder = ddoYMD then + FSelectedTextPart := 1 + else + FSelectedTextPart := 3; + end; + end; + + Invalidate; + end; +end; + +procedure TCustomZVDateTimePicker.SelectTimeTextPart( + const TimeTextPart: TTimeTextPart); +var + B: Boolean; +begin + if FKind in [dtkTime, dtkDateTime] then begin + + if TimeTextPart = ttpAMPM then + B := FTimeFormat = tf12 + else + B := Ord(FTimeDisplay) + 1 >= Ord(TimeTextPart); + + if B then + FSelectedTextPart := 4 + Ord(TimeTextPart); + + end; + Invalidate; +end; + +procedure TCustomZVDateTimePicker.DestroyCalendarForm; +begin + if Assigned(FCalendarForm) then begin + TDTCalendarForm(FCalendarForm).FClosing := True; + FCalendarForm.Release; + FCalendarForm := nil; + end; +end; + +class function TCustomZVDateTimePicker.GetControlClassDefaultSize: TSize; +begin + Result.cx := 102; + Result.cy := 23; +end; + +procedure TCustomZVDateTimePicker.ConfirmChanges; +begin + UpdateIfUserChangedText; + FConfirmedDateTime := FDateTime; +end; + +procedure TCustomZVDateTimePicker.UndoChanges; +begin + FDateTime := FConfirmedDateTime; + UpdateDate; +end; + +{ GetCurrentDateTextPart function + ---------------------------------- + Returns part of Date which is currently selected. + If currently selected text part belongs to time, then this function returns + dtpTime and GetCurrentTimeTextPart function should be used to determine which + part of time is selected. } +function TCustomZVDateTimePicker.GetCurrentDateTextPart: TDateTextPart; +begin + if FSelectedTextPart > 3 then + Result := dtpTime + else begin + case FSelectedTextPart of + 1: Result := dtpDay; + 2: Result := dtpMonth; + 3: Result := dtpYear; + end; + + case FEffectiveDateDisplayOrder of + ddoMDY: if Result = dtpDay then Result := dtpMonth + else if Result = dtpMonth then Result := dtpDay; + ddoYMD: if Result = dtpDay then Result := dtpYear + else if Result = dtpYear then Result := dtpDay; + end; + + end; +end; + +{ GetCurrentTimeTextPart function + ---------------------------------- + Returns part of Time which is currently selected. + Used when GetCurrentDateTextPart returns dtpTime. } +function TCustomZVDateTimePicker.GetCurrentTimeTextPart: TTimeTextPart; +begin + if FSelectedTextPart > 4 then + Result := TTimeTextPart(FSelectedTextPart - 4) + else + Result := ttpHour; +end; + +procedure TCustomZVDateTimePicker.FontChanged(Sender: TObject); +begin + FRecalculatingTextSizesNeeded := True; + inherited FontChanged(Sender); +end; + +{ GetTextOrigin + --------------- + Returns upper left corner of the rectangle where the text is written. + Also used in calculating our preffered size. } +function TCustomZVDateTimePicker.GetTextOrigin: TPoint; +begin + Result.y := BorderSpacing.InnerBorder + BorderWidth; + if Assigned(FCheckBox) then + Result.x := Result.y + FCheckBox.BorderSpacing.Left + FCheckBox.Width + else + Result.x := Result.y; +end; + +procedure TCustomZVDateTimePicker.KeyDown(var Key: Word; Shift: TShiftState); +var + M, L, N: Integer; + K: Word; +begin + Inc(FUserChanging); + try + if FTextEnabled then + inherited KeyDown(Key, Shift); // calls OnKeyDown event + + if (Key = VK_SPACE) then begin + if GetShowCheckBox then + FCheckBox.Checked := not FCheckBox.Checked; + + end else if FTextEnabled then begin + + case Key of + VK_LEFT, VK_RIGHT, VK_OEM_COMMA, VK_OEM_PERIOD, VK_DIVIDE, + VK_OEM_MINUS, VK_SEPARATOR, VK_DECIMAL, VK_SUBTRACT: + begin + K := Key; + Key := 0; + UpdateIfUserChangedText; + if FKind in [dtkDate, dtkDateTime] then + M := 1 + else + M := 4; + + if FKind in [dtkTime, dtkDateTime] then begin + L := Ord(FTimeDisplay) + 5; + if FTimeFormat = tf12 then + N := 8 + else + N := L; + end else begin + N := 3; + L := 3; + end; + + if K = VK_LEFT then begin + if FSelectedTextPart = M then + FSelectedTextPart := N + else if (FSelectedTextPart = N) and (L < N) then + FSelectedTextPart := L + else + Dec(FSelectedTextPart); + end else begin + if FSelectedTextPart = N then + FSelectedTextPart := M + else if (FSelectedTextPart = L) and (L < N) then + FSelectedTextPart := N + else + Inc(FSelectedTextPart); + end; + + Invalidate; + end; + VK_UP: + begin + Key := 0; + UpdateIfUserChangedText; + if not FReadOnly then + IncreaseCurrentTextPart; + end; + VK_DOWN: + begin + Key := 0; + UpdateIfUserChangedText; + if not FReadOnly then + DecreaseCurrentTextPart; + end; + VK_RETURN: + if not FReadOnly then + EditingDone; + + VK_ESCAPE: + if not FReadOnly then begin + UndoChanges; + EditingDone; + end; + VK_N: + if (not FReadOnly) and FNullInputAllowed then + SetDateTime(NullDate); + end; + + end; + finally + Dec(FUserChanging); + end; + +end; + +procedure TCustomZVDateTimePicker.KeyPress(var Key: char); +var + S: String; + DTP: TDateTextPart; + TTP: TTimeTextPart; + N, L: Integer; + YMD: TYMD; + HMSMs: THMSMs; + D, T: TDateTime; + Finished: Boolean; + +begin + if FTextEnabled then begin + Inc(FUserChanging); + try + inherited KeyPress(Key); + + if (not FReadOnly) then begin + Finished := False; + + if FSelectedTextPart = 8 then begin + case upCase(Key) of + 'A': S := 'AM'; + 'P': S := 'PM'; + else + Finished := True; + end; + + end else if Key in ['0'..'9'] then begin + TTP := ttpAMPM; + DTP := GetCurrentDateTextPart; + + if DTP = dtpYear then + N := 4 + else if DTP = dtpTime then begin + TTP := GetCurrentTimeTextPart; + if TTP = ttpMiliSec then + N := 3 + else + N := 2; + end else + N := 2; + + S := Trim(GetSelectedText); + if FUserChangedText and (UTF8Length(S) < N) then begin + S := S + Key; + + if (not FLeadingZeros) and (FSelectedTextPart <= 4) then + while (UTF8Length(S) > 1) and (UTF8Copy(S, 1, 1) = '0') do + UTF8Delete(S, 1, 1); + + end else begin + S := Key; + end; + + if (UTF8Length(S) >= N) then begin + + L := StrToInt(S); + if DTP <> dtpTime then begin + YMD := GetYYYYMMDD(True); + case DTP of + dtpDay: YMD.Day := L; + dtpMonth: YMD.Month := L; + dtpYear: YMD.Year := L; + end; + if not TryEncodeDate(YMD.Year, YMD.Month, YMD.Day, D) then begin + D := MinDate - 1; + end; + if (D < MinDate) or (D > MaxDate) then begin + if N = 4 then begin + UpdateDate; + Finished := True; + end else + S := Key; + end; + end else begin + if (TTP = ttpHour) and (FTimeFormat = tf12) then begin + if not (L in [1..12]) then + S := Key; + + end else begin + + HMSMs := GetHMSMs(True); + case TTP of + ttpHour: HMSMs.Hour := L; + ttpMinute: HMSMs.Minute := L; + ttpSecond: HMSMs.Second := L; + ttpMiliSec: HMSMs.MiliSec := L; + end; + if not TryEncodeTime(HMSMs.Hour, HMSMs.Minute, HMSMs.Second, + HMSMs.MiliSec, T) then + S := Key; + + end; + end; + + end; + end else + Finished := True; + + if (not Finished) and (GetSelectedText <> S) then begin + if (not FUserChangedText) and DateIsNull then + if FSelectedTextPart <= 3 then + DateTime := SysUtils.Date + else + DateTime := SysUtils.Now; + + if FSelectedTextPart <= 3 then + FTextPart[FSelectedTextPart] := S + else + FTimeText[TTimeTextPart(FSelectedTextPart - 4)] := S; + + FUserChangedText := True; + + Invalidate; + end; + + end; + + finally + Dec(FUserChanging); + end; + + end; +end; + +{ SelectTextPartUnderMouse + -------------------------- + This procedure determines which text part (date or time part -- day, month, + year, hour, minute...) should be selected in response to mouse message. + Used in MouseDown and DoMouseWheel methods. } +procedure TCustomZVDateTimePicker.SelectTextPartUnderMouse(XMouse: Integer); +var + M, NX: Integer; + InTime: Boolean; +begin + UpdateIfUserChangedText; + SetFocusIfPossible; + + if Focused then begin +// Calculating mouse position inside text +// in order to select date part under mouse cursor. + FSelectedTextPart := 8; + NX := XMouse - GetTextOrigin.x; + + if FKind = dtkDateTime then begin + if NX >= FDateWidth + FDigitWidth then begin + InTime := True; + NX := NX - FDateWidth - 2 * FDigitWidth; + end else + InTime := False; + end else + InTime := FKind = dtkTime; + + if InTime then begin + if (FTimeFormat = tf24) or + (NX < FTimeWidth - FAMPMWidth - FDigitWidth div 2) then begin + M := 2 * FDigitWidth + FTimeSeparatorWidth div 2; + if M > NX then + FSelectedTextPart := 4 + else begin + if FTimeDisplay = tdHM then + FSelectedTextPart := 5 + else begin + M := M + FTimeSeparatorWidth + 2 * FDigitWidth; + if M > NX then + FSelectedTextPart := 5 + else begin + if FTimeDisplay = tdHMS then + FSelectedTextPart := 6 + else begin + M := M + FTimeSeparatorWidth + 2 * FDigitWidth; + if M > NX then + FSelectedTextPart := 6 + else + FSelectedTextPart := 7; + end; + end; + end; + end; + end; + + end else begin + M := 2 * FDigitWidth; + if FEffectiveDateDisplayOrder = ddoYMD then + M := 2 * M; + Inc(M, FSeparatorWidth div 2); + + if M > NX then begin + FSelectedTextPart := 1; + end else begin + M := M + FSeparatorWidth + 2 * FDigitWidth; + if M > NX then begin + FSelectedTextPart := 2; + end else begin + FSelectedTextPart := 3 + end; + end; + end; + Invalidate; +//------------------------------------------------------- + end; +end; + +procedure TCustomZVDateTimePicker.MouseDown(Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if FTextEnabled then begin + SelectTextPartUnderMouse(X); + inherited MouseDown(Button, Shift, X, Y); + end else + SetFocusIfPossible; + +end; + +function TCustomZVDateTimePicker.DoMouseWheel(Shift: TShiftState; + WheelDelta: Integer; MousePos: TPoint): Boolean; +begin + Result := False; + if FTextEnabled then begin + SelectTextPartUnderMouse(MousePos.x); + if not FReadOnly then begin + Inc(FUserChanging); + try + if WheelDelta < 0 then + DecreaseCurrentTextPart + else + IncreaseCurrentTextPart; + + Result := True; + finally + Dec(FUserChanging); + end; + end; + end; +end; + +procedure TCustomZVDateTimePicker.CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); +var + TextOrigin: TPoint; + M: Integer; + +begin + RecalculateTextSizesIfNeeded; + TextOrigin := GetTextOrigin; + + // We must use TextOrigin's x + y (x is, of corse, left margin, but not right + // margin if check box is shown. Hower, y always equals right margin). + PreferredWidth := TextOrigin.x + TextOrigin.y; + + if Assigned(FUpDown) then + Inc(PreferredWidth, FUpDown.Width) + else if Assigned(FArrowButton) then + Inc(PreferredWidth, FArrowButton.Width); + + PreferredWidth := PreferredWidth + FTextWidth; + + M := Width - ClientWidth; + PreferredWidth := PreferredWidth + M; + + PreferredHeight := 2 * TextOrigin.y + FTextHeight + M; +end; + +procedure TCustomZVDateTimePicker.IncreaseCurrentTextPart; +begin + if DateIsNull then begin + if FSelectedTextPart <= 3 then + SetDateTime(SysUtils.Date) + else + SetDateTime(SysUtils.Now); + + end else begin + case GetCurrentDateTextPart of + dtpDay: IncreaseDay; + dtpMonth: IncreaseMonth; + dtpYear: IncreaseYear; + else + case GetCurrentTimeTextPart of + ttpHour: IncreaseHour; + ttpMinute: IncreaseMinute; + ttpSecond: IncreaseSecond; + ttpMiliSec: IncreaseMiliSec; + ttpAMPM: ChangeAMPM; + end; + end; + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseCurrentTextPart; +begin + if DateIsNull then begin + if FSelectedTextPart <= 3 then + SetDateTime(SysUtils.Date) + else + SetDateTime(SysUtils.Now); + + end else begin + case GetCurrentDateTextPart of + dtpDay: DecreaseDay; + dtpMonth: DecreaseMonth; + dtpYear: DecreaseYear; + else + case GetCurrentTimeTextPart of + ttpHour: DecreaseHour; + ttpMinute: DecreaseMinute; + ttpSecond: DecreaseSecond; + ttpMiliSec: DecreaseMiliSec; + ttpAMPM: ChangeAMPM; + end; + end; + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseMonth; +var + YMD: TYMD; + N: Word; +begin + SelectMonth; + YMD := GetYYYYMMDD(True); + + if YMD.Month >= 12 then + YMD.Month := 1 + else + Inc(YMD.Month); + + N := NumberOfDaysInMonth(YMD.Month, YMD.Year); + if YMD.Day > N then + YMD.Day := N; + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.IncreaseYear; +var + YMD: TYMD; +begin + SelectYear; + YMD := GetYYYYMMDD(True); + + Inc(YMD.Year); + if (YMD.Month = 2) and (YMD.Day > 28) and (not IsLeapYear(YMD.Year)) then + YMD.Day := 28; + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.IncreaseDay; +var + YMD: TYMD; +begin + SelectDay; + YMD := GetYYYYMMDD(True); + + if YMD.Day >= NumberOfDaysInMonth(YMD.Month, YMD.Year) then + YMD.Day := 1 + else + Inc(YMD.Day); + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.DecreaseMonth; +var + YMD: TYMD; + N: Word; +begin + SelectMonth; + YMD := GetYYYYMMDD(True); + + if YMD.Month <= 1 then + YMD.Month := 12 + else + Dec(YMD.Month); + + N := NumberOfDaysInMonth(YMD.Month, YMD.Year); + if YMD.Day > N then + YMD.Day := N; + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.DecreaseYear; +var + YMD: TYMD; +begin + SelectYear; + YMD := GetYYYYMMDD(True); + Dec(YMD.Year); + if (YMD.Month = 2) and (YMD.Day > 28) and (not IsLeapYear(YMD.Year)) then + YMD.Day := 28; + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.DecreaseDay; +var + YMD: TYMD; +begin + SelectDay; + YMD := GetYYYYMMDD(True); + + if YMD.Day <= 1 then + YMD.Day := NumberOfDaysInMonth(YMD.Month, YMD.Year) + else + Dec(YMD.Day); + + SetYYYYMMDD(YMD); +end; + +procedure TCustomZVDateTimePicker.IncreaseHour; +var + HMSMs: THMSMs; +begin + SelectHour; + HMSMs := GetHMSMs(True); + + if HMSMs.Hour >= 23 then + HMSMs.Hour := 0 + else + Inc(HMSMs.Hour); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.IncreaseMinute; +var + HMSMs: THMSMs; +begin + SelectMinute; + HMSMs := GetHMSMs(True); + + if HMSMs.Minute >= 59 then + HMSMs.Minute := 0 + else + Inc(HMSMs.Minute); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.IncreaseSecond; +var + HMSMs: THMSMs; +begin + SelectSecond; + HMSMs := GetHMSMs(True); + + if HMSMs.Second >= 59 then + HMSMs.Second := 0 + else + Inc(HMSMs.Second); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.IncreaseMiliSec; +var + HMSMs: THMSMs; +begin + SelectMiliSec; + HMSMs := GetHMSMs(True); + + if HMSMs.MiliSec >= 999 then + HMSMs.MiliSec := 0 + else + Inc(HMSMs.MiliSec); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.DecreaseHour; +var + HMSMs: THMSMs; +begin + SelectHour; + HMSMs := GetHMSMs(True); + + if HMSMs.Hour <= 0 then + HMSMS.Hour := 23 + else + Dec(HMSMs.Hour); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.DecreaseMinute; +var + HMSMs: THMSMs; +begin + SelectMinute; + HMSMs := GetHMSMs(True); + + if HMSMs.Minute <= 0 then + HMSMs.Minute := 59 + else + Dec(HMSMs.Minute); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.DecreaseSecond; +var + HMSMs: THMSMs; +begin + SelectSecond; + HMSMs := GetHMSMs(True); + + if HMSMs.Second <= 0 then + HMSMs.Second := 59 + else + Dec(HMSMs.Second); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.DecreaseMiliSec; +var + HMSMs: THMSMs; +begin + SelectMiliSec; + HMSMs := GetHMSMs(True); + + if HMSMs.MiliSec <= 0 then + HMSMs.MiliSec := 999 + else + Dec(HMSMs.MiliSec); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.ChangeAMPM; +var + HMSMs: THMSMs; +begin + SelectAMPM; + HMSMs := GetHMSMs(True); + + if HMSMs.Hour >= 12 then + Dec(HMSMS.Hour, 12) + else + Inc(HMSMS.Hour, 12); + + SetHMSMs(HMSMs); +end; + +procedure TCustomZVDateTimePicker.UpdateDate; +var + W: Array[1..3] of Word; + WT: Array[TTimeTextPart] of Word; + YearPos, I: Integer; + TTP, TTPEnd: TTimeTextPart; +begin + FUserChangedText := False; + + if not (DateIsNull or FJumpMinMax) then begin + if Int(FDateTime) > FMaxDate then + FDateTime := ComposeDateTime(FMaxDate, FDateTime); + + if FDateTime < FMinDate then + FDateTime := ComposeDateTime(FMinDate, FDateTime); + end; + + if FKind in [dtkTime, dtkDateTime] then begin + if DateIsNull then begin + FTimeText[ttpHour] := '99'; + FTimeText[ttpMinute] := '99'; + + FTimeText[ttpMiliSec] := ''; + if FTimeDisplay >= tdHMS then begin + FTimeText[ttpSecond] := '99'; + if FTimeDisplay >= tdHMSMs then + FTimeText[ttpMiliSec] := '999'; + end else + FTimeText[ttpSecond] := ''; + + if FTimeFormat = tf12 then + FTimeText[ttpAMPM] := 'XX' + else + FTimeText[ttpAMPM] := ''; + + end else begin + case FTimeDisplay of + tdHMSMs: TTPEnd := ttpMiliSec; + tdHMS: TTPEnd := ttpSecond; + else + TTPEnd := ttpMinute; + end; + + DecodeTime(FDateTime, WT[ttpHour], WT[ttpMinute], WT[ttpSecond], WT[ttpMiliSec]); + + if FTimeFormat = tf12 then begin + if WT[ttpHour] < 12 then begin + FTimeText[ttpAMPM] := 'AM'; + if WT[ttpHour] = 0 then + WT[ttpHour] := 12; + end else begin + FTimeText[ttpAMPM] := 'PM'; + if WT[ttpHour] > 12 then + Dec(WT[ttpHour], 12); + end; + end else + FTimeText[ttpAMPM] := ''; + + if FLeadingZeros then + FTimeText[ttpHour] := RightStr('0' + IntToStr(WT[ttpHour]), 2) + else + FTimeText[ttpHour] := IntToStr(WT[ttpHour]); + + for TTP := ttpMinute to ttpMiliSec do begin + if TTP <= TTPEnd then begin + if TTP = ttpMiliSec then + FTimeText[TTP] := RightStr('00' + IntToStr(WT[TTP]), 3) + else + FTimeText[TTP] := RightStr('0' + IntToStr(WT[TTP]), 2); + end else + FTimeText[TTP] := ''; + end; + + end; + end else + for TTP := Low(TTimeTextPart) to High(TTimeTextPart) do + FTimeText[TTP] := ''; + + if FKind in [dtkDate, dtkDateTime] then begin + if DateIsNull then begin + if FEffectiveDateDisplayOrder = ddoYMD then begin + FTextPart[1] := '0000'; + FTextPart[3] := '00'; + end else begin + FTextPart[1] := '00'; + FTextPart[3] := '0000'; + end; + FTextPart[2] := '00'; + + end else begin + DecodeDate(FDateTime, W[3], W[2], W[1]); + YearPos := 3; + case FEffectiveDateDisplayOrder of + ddoMDY: + Exchange(W[1], W[2]); + + ddoYMD: + begin + Exchange(W[1], W[3]); + YearPos := 1; + end; + end; + + for I := Low(FTextPart) to High(FTextPart) do begin + if I = YearPos then + FTextPart[I] := RightStr('000' + IntToStr(W[I]), 4) + else if FLeadingZeros then + FTextPart[I] := RightStr('0' + IntToStr(W[I]), 2) + else + FTextPart[I] := IntToStr(W[I]); + + end; + end; + + end else + for I := Low(FTextPart) to High(FTextPart) do + FTextPart[I] := ''; + + if FUserChanging > 0 then // this means that the change is caused by user interaction + Change + else + FConfirmedDateTime := FDateTime; + + Invalidate; +end; + +procedure TCustomZVDateTimePicker.DoEnter; +begin + inherited DoEnter; + Invalidate; +end; + +procedure TCustomZVDateTimePicker.DoExit; +begin + inherited DoExit; + Invalidate; +end; + +procedure TCustomZVDateTimePicker.Click; +begin + if FTextEnabled then + inherited Click; +end; + +procedure TCustomZVDateTimePicker.DblClick; +begin + if FTextEnabled then + inherited DblClick; +end; + +procedure TCustomZVDateTimePicker.MouseUp(Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if FTextEnabled then + inherited MouseUp(Button, Shift, X, Y); +end; + +procedure TCustomZVDateTimePicker.KeyUp(var Key: Word; Shift: TShiftState); +begin + if FTextEnabled then + inherited KeyUp(Key, Shift); +end; + +procedure TCustomZVDateTimePicker.UTF8KeyPress(var UTF8Key: TUTF8Char); +begin + if FTextEnabled then + inherited UTF8KeyPress(UTF8Key); +end; + +procedure TCustomZVDateTimePicker.SelectDay; +begin + SelectDateTextPart(dtpDay); +end; + +procedure TCustomZVDateTimePicker.SelectMonth; +begin + SelectDateTextPart(dtpMonth); +end; + +procedure TCustomZVDateTimePicker.SelectYear; +begin + SelectDateTextPart(dtpYear); +end; + +procedure TCustomZVDateTimePicker.SelectHour; +begin + SelectTimeTextPart(ttpHour); +end; + +procedure TCustomZVDateTimePicker.SelectMinute; +begin + SelectTimeTextPart(ttpMinute); +end; + +procedure TCustomZVDateTimePicker.SelectSecond; +begin + SelectTimeTextPart(ttpSecond); +end; + +procedure TCustomZVDateTimePicker.SelectMiliSec; +begin + SelectTimeTextPart(ttpMiliSec); +end; + +procedure TCustomZVDateTimePicker.SelectAMPM; +begin + SelectTimeTextPart(ttpAMPM); +end; + +procedure TCustomZVDateTimePicker.SetEnabled(Value: Boolean); +begin + if GetEnabled <> Value then begin + inherited SetEnabled(Value); + CheckTextEnabled; + Invalidate; + end; +end; + +procedure TCustomZVDateTimePicker.SetAutoSize(Value: Boolean); +begin + if AutoSize <> Value then begin + if Value then + InvalidatePreferredSize; + + inherited SetAutoSize(Value); + end; +end; + +// I had to override CreateWnd, because in design time on Linux Lazarus crashes +// if we try to do anchoring of child controls in constructor. +// Therefore, I needed to ensure that controls anchoring does not take place +// before CreateWnd has done. So, I moved all anchoring code to a procedure +// ArrangeCtrls and introduced a boolean field FDoNotArrangeControls which +// prevents that code from executing before CreateWnd. +//!!! Later, I simplified the arranging procedure, so maybe it can be done now +// before window creation is done. It's better to leave this delay system, +// anyway -- we might change anchoring code again for some reason. +procedure TCustomZVDateTimePicker.CreateWnd; +begin + inherited CreateWnd; + + if FDoNotArrangeControls then begin { This field is set to True in constructor. + Its purpose is to prevent control anchoring until this point. That's because + on Linux Lazarus crashes when control is dropped on form in designer if + particular anchoring code executes before CreateWnd has done its job. } + FDoNotArrangeControls := False; + ArrangeCtrls; + end; +end; + +procedure TCustomZVDateTimePicker.SetDateTimeJumpMinMax(const AValue: TDateTime); +begin + FJumpMinMax := True; + try + SetDateTime(AValue); + finally + FJumpMinMax := False; + end; +end; + +procedure TCustomZVDateTimePicker.ArrangeCtrls; +begin + if not FDoNotArrangeControls then begin //Read the note above CreateWnd procedure. + DisableAlign; + try + if GetShowCheckBox then begin + FCheckBox.Align := alLeft; + FCheckBox.BorderSpacing.Left := 2; + FCheckBox.BringToFront; + FCheckBox.OnChange := @CheckBoxChange; + end; + + CheckTextEnabled; + InvalidatePreferredSize; + AdjustSize; + + Invalidate; + finally + EnableAlign; + end; + end; +end; + +procedure TCustomZVDateTimePicker.Change; +begin + if Assigned(FOnChange) then + FOnChange(Self); +end; + +procedure TCustomZVDateTimePicker.SelectDate; +begin + if FSelectedTextPart > 3 then + SelectDay; +end; + +procedure TCustomZVDateTimePicker.SelectTime; +begin + if FSelectedTextPart < 4 then + SelectHour; +end; + +procedure TCustomZVDateTimePicker.Paint; +var + I, M, N, K: Integer; + DD: Array[1..8] of Integer; + R: TRect; + SelectStep: 0..8; + TextStyle: TTextStyle; + +begin + if ClientRectNeedsInterfaceUpdate then // In Qt widgetset, this solves the + DoAdjustClientRectChange; // problem of dispositioned client rect. + + if FRecalculatingTextSizesNeeded then begin + if AutoSize then begin + InvalidatePreferredSize; + AdjustSize; + end; + + RecalculateTextSizesIfNeeded; + end; + + TextStyle := Canvas.TextStyle; + + Canvas.Brush.Style := bsSolid; + Canvas.Brush.Color := Color; + Canvas.FillRect(ClientRect); + + R.TopLeft := GetTextOrigin; + + M := 2 * R.Top + FTextHeight; + M := (ClientHeight - M) div 2; + + Inc(R.Top, M); + + R.Bottom := R.Top + FTextHeight; + + TextStyle.Layout := tlCenter; + TextStyle.Wordbreak := False; + TextStyle.Opaque := False; + if DateIsNull and (FTextForNullDate > '') + and (not (FTextEnabled and Focused)) then begin + + R.Right := MaxInt; + + TextStyle.Alignment := taLeftJustify; + + if FTextEnabled then + Canvas.Font.Color := Font.Color + else + Canvas.Font.Color := clGrayText; + + Canvas.TextRect(R, R.Left, R.Top, FTextForNullDate, TextStyle); + + end else begin + TextStyle.Alignment := taRightJustify; + + SelectStep := 0; + if FTextEnabled then begin + Canvas.Font.Color := Font.Color; + if Focused then + SelectStep := FSelectedTextPart; + end else begin + Canvas.Font.Color := clGrayText; + end; + + if FKind in [dtkDate, dtkDateTime] then begin + DD[2] := 2 * FDigitWidth; + if FEffectiveDateDisplayOrder = ddoYMD then begin + DD[1] := 4 * FDigitWidth; + DD[3] := 2 * FDigitWidth; + end else begin + DD[1] := 2 * FDigitWidth; + DD[3] := 4 * FDigitWidth; + end; + M := 1; + end else begin + M := 4; + //for I := 1 to 3 do DD[I] := 0; + end; + + if FKind in [dtkTime, dtkDateTime] then begin + DD[4] := 2 * FDigitWidth; + DD[5] := 2 * FDigitWidth; + + if FTimeDisplay = tdHMSMs then begin + DD[7] := 3 * FDigitWidth; + DD[6] := 2 * FDigitWidth; + K := 7; + end else begin + DD[7] := 0; + if FTimeDisplay = tdHM then begin + DD[6] := 0; + K := 5; + end else begin + DD[6] := 2 * FDigitWidth; + K := 6; + end; + end; + + if FTimeFormat = tf12 then begin + N := 8; + DD[8] := FAMPMWidth; + end else begin + DD[8] := 0; + N := K; + end; + + end else begin + N := 3; + K := 3; + end; + + for I := M to N do begin + if DD[I] <> 0 then begin + if SelectStep = I then begin + TextStyle.Opaque := True; + Canvas.Brush.Color := clHighlight; + Canvas.Font.Color := clHighlightText; + end; + + R.Right := R.Left + DD[I]; + if I <= 3 then + Canvas.TextRect(R, R.Left, R.Top, FTextPart[I], TextStyle) + else + Canvas.TextRect(R, R.Left, R.Top, FTimeText[TTimeTextPart(I - 4)], TextStyle); + + R.Left := R.Right; + + if SelectStep = I then begin + TextStyle.Opaque := False; + Canvas.Brush.Color := Color; + Canvas.Font.Color := Self.Font.Color; + end; + + if I < 3 then begin + R.Right := R.Left + FSeparatorWidth; + Canvas.TextRect(R, R.Left, R.Top, FDateSeparator, TextStyle); + end else if I > 3 then begin + if I = K then begin + R.Right := R.Left + FDigitWidth; + end else if I < K then begin + R.Right := R.Left + FTimeSeparatorWidth; + Canvas.TextRect(R, R.Left, R.Top, FTimeSeparator, TextStyle); + end; + end else begin + if FTrailingSeparator then begin + R.Right := R.Left + FSepNoSpaceWidth; + Canvas.TextRect(R, R.Left, R.Top, + TrimRight(FDateSeparator), TextStyle); + end; + if FKind = dtkDateTime then + R.Right := R.Right + 2 * FDigitWidth; + + end; + R.Left := R.Right; + end; + end; + + end; + + inherited Paint; +end; + +procedure TCustomZVDateTimePicker.EditingDone; +begin + if FNoEditingDone <= 0 then begin + ConfirmChanges; + + inherited EditingDone; + end; +end; + +procedure TCustomZVDateTimePicker.ArrowMouseDown(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + DropDownCalendarForm; +end; + +procedure TCustomZVDateTimePicker.UpDownClick(Sender: TObject; + Button: TUDBtnType); +begin + SetFocusIfPossible; + + if not FReadOnly then begin + if Button = btNext then + IncreaseCurrentTextPart + else + DecreaseCurrentTextPart; + end; +end; + +procedure TCustomZVDateTimePicker.DoDropDown; +begin + if Assigned(FOnDropDown) then + FOnDropDown(Self); +end; + +procedure TCustomZVDateTimePicker.DoCloseUp; +begin + if Assigned(FOnCloseUp) then + FOnCloseUp(Self); +end; + +function TCustomZVDateTimePicker.GetChecked: Boolean; +begin + Result := (not Assigned(FCheckBox)) or (FCheckBox.State = cbChecked); +end; + +{ DrawArrowButtonGlyph + ---------------------- + Draws the arrow shape on button (when DateMode dmComboBox is set). } +procedure TCustomZVDateTimePicker.DrawArrowButtonGlyph; +const + ArrowColor = TColor($8D665A); +begin +// First I ment to put arrow images in a lrs file. In my opinion, however, that +// wouldn't be an elegant option for so simple shapes. + + if Assigned(FArrowButton) then begin + FArrowButton.Glyph.SetSize(9, 6); + FArrowButton.Glyph.Canvas.Brush.Style := bsSolid; + FArrowButton.Glyph.Canvas.Brush.Color := clSkyBlue; + FArrowButton.Glyph.Canvas.FillRect(0, 0, 9, 6); + FArrowButton.Glyph.Canvas.Pen.Color := ArrowColor; + FArrowButton.Glyph.Canvas.Brush.Color := FArrowButton.Glyph.Canvas.Pen.Color; + +{ Let's draw shape of the arrow on the button: } + case FArrowShape of + asClassicLarger: + { triangle: } + FArrowButton.Glyph.Canvas.Polygon([Point(0, 1), Point(8, 1), + Point(4, 5)]); + asClassicSmaller: + { triangle -- smaller variant: } + FArrowButton.Glyph.Canvas.Polygon([Point(1, 2), Point(7, 2), + Point(4, 5)]); + asModernLarger: + { modern: } + FArrowButton.Glyph.Canvas.Polygon([Point(0, 1), Point(1, 0), + Point(4, 3), Point(7, 0), Point(8, 1), Point(4, 5)]); + asModernSmaller: + { modern -- smaller variant: } + FArrowButton.Glyph.Canvas.Polygon([Point(1, 2), Point(2, 1), + Point(4, 3), Point(6, 1), Point(7, 2), Point(4, 5)]); + asYetAnotherShape: + { something in between, not very pretty: } + FArrowButton.Glyph.Canvas.Polygon([Point(0, 1), Point(1, 0), + Point(2, 1), Point(6, 1),Point(7, 0), Point(8, 1), Point(4, 5)]); + end; + + FArrowButton.Glyph.Mask(clSkyBlue); + end; +end; + +function TCustomZVDateTimePicker.AreSeparatorsStored: Boolean; +begin + Result := not FUseDefaultSeparators; +end; + +function TCustomZVDateTimePicker.GetDate: TDate; +begin + if DateIsNull then + Result := NullDate + else + Result := Int(FDateTime); +end; + +function TCustomZVDateTimePicker.GetDateTime: TDateTime; +begin + if DateIsNull then + Result := NullDate + else + Result := FDateTime; +end; + +function TCustomZVDateTimePicker.GetShowCheckBox: Boolean; +begin + Result := Assigned(FCheckBox); +end; + +function TCustomZVDateTimePicker.GetTime: TTime; +begin + if DateIsNull then + Result := NullDate + else + Result := Abs(Frac(FDateTime)); +end; + +procedure TCustomZVDateTimePicker.SetArrowShape(const AValue: TArrowShape); +begin + if FArrowShape = AValue then Exit; + + FArrowShape := AValue; + DrawArrowButtonGlyph; +end; + +procedure TCustomZVDateTimePicker.SetCenturyFrom(const AValue: Word); +begin + if FCenturyFrom = AValue then Exit; + + FCenturyFrom := AValue; + AdjustEffectiveCenturyFrom; +end; + +procedure TCustomZVDateTimePicker.CheckBoxChange(Sender: TObject); +begin + CheckTextEnabled; + SetFocusIfPossible; + + if Assigned(FOnCheckBoxChange) then + FOnCheckBoxChange(Sender); + + Invalidate; +end; + +procedure TCustomZVDateTimePicker.SetFocusIfPossible; +var + F: TCustomForm; + +begin + Inc(FNoEditingDone); + try + F := GetParentForm(Self); + + if Assigned(F) and F.CanFocus and CanTab then + SetFocus; + + finally + Dec(FNoEditingDone); + end; +end; + +procedure TCustomZVDateTimePicker.WMKillFocus(var Message: TLMKillFocus); +begin + // On Qt it seems that WMKillFocus happens even when focus jumps to some other + // form. This behaviour differs from win and gtk 2 (where it happens only when + // focus jumps to other control on the same form) and we should prevent it at + // least for our calendar, because it triggers EditingDone. + if Screen.ActiveCustomForm <> FCalendarForm then + inherited WMKillFocus(Message); +end; + +{$ifdef LCLGtk2} +// On Gtk2, it seems that if a non-modal form is shown on top +// of a modal one, it can't get user interaction. So it is useless then. +// Therefore, if our parent is shown modally, we must show the calendar +// on a modal form too. + {$if lcl_fullversion < 00093100} + // This seems to be fixed, so this is not needed in recent Lazarus versions. + {$define show_modally_on_modal_form} + {$endif} +{$endif} + +procedure TCustomZVDateTimePicker.DropDownCalendarForm; +{$ifdef show_modally_on_modal_form} +var + F: TCustomForm; +{$endif} +begin + SetFocusIfPossible; + + if FAllowDroppingCalendar then begin + if not (FReadOnly or Assigned(FCalendarForm) + or (csDesigning in ComponentState)) then begin + FCalendarForm := TDTCalendarForm.CreateNewDTCalendarForm(nil, Self); + + {$ifdef show_modally_on_modal_form} + F := GetParentForm(Self); + if Assigned(F) and (fsModal in F.FormState) then + FCalendarForm.ShowModal + else + {$endif} + FCalendarForm.Show; + end; + + end else begin + DestroyCalendarForm; + FAllowDroppingCalendar := True; + end; + +end; + +type + + { TDTUpDown } + +{ The two buttons contained by UpDown control are never disabled in original + UpDown class. This class is defined here to override this behaviour. } + TDTUpDown = class(TCustomUpDown) + private + DTPicker: TCustomZVDateTimePicker; + protected + procedure SetEnabled(Value: Boolean); override; + procedure CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); override; + procedure WndProc(var Message: TLMessage); override; + end; + + { TDTSpeedButton } + + TDTSpeedButton = class(TCustomSpeedButton) + private + DTPicker: TCustomZVDateTimePicker; + protected + procedure CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); override; + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + override; + end; + +{ TDTUpDown } + +{ When our UpDown control gets enabled/disabled, the two its buttons' Enabled + property is set accordingly. } +procedure TDTUpDown.SetEnabled(Value: Boolean); + + procedure SetEnabledForAllChildren(AWinControl: TWinControl); + var + I: Integer; + C: TControl; + begin + for I := 0 to AWinControl.ControlCount - 1 do begin + C := AWinControl.Controls[I]; + C.Enabled := Value; + + if C is TWinControl then + SetEnabledForAllChildren(TWinControl(C)); + + end; + end; + +begin + inherited SetEnabled(Value); + + SetEnabledForAllChildren(Self); +end; + +{ Our UpDown control is always alligned, but setting its PreferredHeight + uncoditionally to 1 prevents the UpDown to mess with our PreferredHeight. + The problem is that if we didn't do this, when our Height is greater than + really preffered, UpDown prevents it to be set correctly when we set AutoSize + to True. } +procedure TDTUpDown.CalculatePreferredSize(var PreferredWidth, PreferredHeight: + integer; WithThemeSpace: Boolean); +begin + inherited CalculatePreferredSize(PreferredWidth, PreferredHeight, + WithThemeSpace); + + PreferredHeight := 1; +end; + +{ We don't want to let EditingDone event to fire each time up-down buttons get + clicked. That is why WndProc is overriden. } +procedure TDTUpDown.WndProc(var Message: TLMessage); +begin + if ((Message.msg >= LM_MOUSEFIRST) and (Message.msg <= LM_MOUSELAST)) + or ((Message.msg >= LM_MOUSEFIRST2) and (Message.msg <= LM_MOUSELAST2)) then begin + + Inc(DTPicker.FNoEditingDone); + try + inherited WndProc(Message); + finally + Dec(DTPicker.FNoEditingDone); + end + + end else + inherited WndProc(Message); + +end; + +{ TDTSpeedButton } + +{ See the coment above TDTUpDown.CalculatePreferredSize } +procedure TDTSpeedButton.CalculatePreferredSize(var PreferredWidth, + PreferredHeight: integer; WithThemeSpace: Boolean); +begin + inherited CalculatePreferredSize(PreferredWidth, PreferredHeight, + WithThemeSpace); + + PreferredHeight := 1; +end; + +{ Prevent EditingDone to fire whenever the SpeedButton gets clicked } +procedure TDTSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, + Y: Integer); +begin + Inc(DTPicker.FNoEditingDone); + try + inherited MouseDown(Button, Shift, X, Y); + finally + Dec(DTPicker.FNoEditingDone); + end; +end; + +procedure TCustomZVDateTimePicker.UpdateShowArrowButton( + NewDateMode: TDTDateMode; NewKind: TDateTimeKind); + + procedure CreateArrowBtn; + begin + if not Assigned(FArrowButton) then begin + DestroyCalendarForm; + DestroyUpDown; + + FArrowButton := TDTSpeedButton.Create(Self); + FArrowButton.ControlStyle := FArrowButton.ControlStyle + + [csNoFocus, csNoDesignSelectable]; + TDTSpeedButton(FArrowButton).DTPicker := Self; + FArrowButton.SetBounds(0, 0, 17, 1); + FArrowButton.Align := alRight; + FArrowButton.BringToFront; + + DrawArrowButtonGlyph; + + FArrowButton.Parent := Self; + FAllowDroppingCalendar := True; + + TDTSpeedButton(FArrowButton).OnMouseDown := @ArrowMouseDown; + + end; + end; + + procedure CreateUpDown; + begin + if not Assigned(FUpDown) then begin + DestroyArrowBtn; + + FUpDown := TDTUpDown.Create(Self); + FUpDown.ControlStyle := FUpDown.ControlStyle + + [csNoFocus, csNoDesignSelectable]; + + TDTUpDown(FUpDown).DTPicker := Self; + + FUpDown.SetBounds(0, 0, 15, 1); + FUpDown.Align := alRight; + FUpDown.BringToFront; + + FUpDown.Parent := Self; + + TDTUpDown(FUPDown).OnClick := @UpDownClick; + + end; + end; + +var + ReallyShowArrowButton: Boolean; + +begin + if NewDateMode = dmNone then begin + DestroyArrowBtn; + DestroyUpDown; + + end else begin + ReallyShowArrowButton := (NewDateMode = dmComboBox) and (NewKind <> dtkTime); + + if (ReallyShowArrowButton <> Assigned(FArrowButton)) or + (Assigned(FArrowButton) = Assigned(FUpDown)) then begin + + if ReallyShowArrowButton then + CreateArrowBtn + else + CreateUpDown; + + ArrangeCtrls; + end; + + end; +end; + +procedure TCustomZVDateTimePicker.DestroyUpDown; +begin + if Assigned(FUpDown) then begin + TDTUpDown(FUPDown).OnClick := nil; + FreeAndNil(FUpDown); + end; +end; + +procedure TCustomZVDateTimePicker.DestroyArrowBtn; +begin + if Assigned(FArrowButton) then begin + TDTSpeedButton(FArrowButton).OnMouseDown := nil; + DestroyCalendarForm; + FreeAndNil(FArrowButton); + end; +end; + +constructor TCustomZVDateTimePicker.Create(AOwner: TComponent); +var + I: Integer; + TTP: TTimeTextPart; +begin + inherited Create(AOwner); + + with GetControlClassDefaultSize do + SetInitialBounds(0, 0, cx, cy); + + FNoEditingDone := 0; + FArrowShape := asModernSmaller; + FAllowDroppingCalendar := True; + + FOnDropDown := nil; + FOnCloseUp := nil; + + ParentColor := False; + FCheckBox := nil; + FArrowButton := nil; + FUpDown := nil; + + FKind := dtkDate; + FNullInputAllowed := True; + + { Thanks to Luiz Américo for this: + Lazarus ignores empty string when saving to lrs. Therefore, the problem + is, when TextForNullDate is set to an empty string and after the project + is saved and opened again, then, this property gets default value NULL + instead of empty string. The following condition seems to be a workaround + for this. } + if (AOwner = nil) or not (csReading in Owner.ComponentState) then + FTextForNullDate := 'NULL'; + + FCenturyFrom := 1941; + FRecalculatingTextSizesNeeded := True; + FOnChange := nil; + FOnCheckBoxChange := nil; + FSeparatorWidth := 0; + FSepNoSpaceWidth := 0; + FDigitWidth := 0; + FTimeSeparatorWidth := 0; + FAMPMWidth := 0; + FDateWidth := 0; + FTimeWidth := 0; + FTextWidth := 0; + FTextHeight := 0; + + for I := Low(FTextPart) to High(FTextPart) do + FTextPart[I] := ''; + + for TTP := Low(TTimeTextPart) to High(TTimeTextPart) do + FTimeText[TTP] := ''; + + FTimeDisplay := tdHMS; + FTimeFormat := tf24; + + FLeadingZeros := True; + FUserChanging := 0; + FReadOnly := False; + FDateTime := SysUtils.Now; + FConfirmedDateTime := FDateTime; + FMinDate := TheSmallestDate; + FMaxDate := TheBiggestDate; + FTrailingSeparator := False; + FDateDisplayOrder := ddoTryDefault; + FSelectedTextPart := 1; + FUseDefaultSeparators := True; + FDateSeparator := DefaultFormatSettings.DateSeparator; + FTimeSeparator := DefaultFormatSettings.TimeSeparator; + FEffectiveCenturyFrom := FCenturyFrom; + FJumpMinMax := False; + + ParentColor := False; + TabStop := True; + BorderWidth := 2; + BorderStyle := bsSingle; + ParentFont := True; + AutoSize := True; + + FTextEnabled := True; + FCalendarForm := nil; + FDoNotArrangeControls := True; + + AdjustEffectiveDateDisplayOrder; + + UpdateDate; + + DateMode := dmComboBox; +end; + +destructor TCustomZVDateTimePicker.Destroy; +begin + FDoNotArrangeControls := True; + DestroyArrowBtn; + DestroyUpDown; + SetShowCheckBox(False); + + inherited Destroy; +end; + +function TCustomZVDateTimePicker.DateIsNull: Boolean; +begin + Result := IsNullDate(FDateTime); +end; + +end. diff --git a/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepickerpropedit.pas b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepickerpropedit.pas new file mode 100644 index 000000000..b51cd3bb4 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.4/zvdatetimepickerpropedit.pas @@ -0,0 +1,495 @@ +{ +ZVDateTimePickerPropEdit +- - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + +Last change: August 2012. + + This unit is part of ZVDateTimeCtrls package for Lazarus. It contains +component and property editors for TZVDateTimePicker control. + +----------------------------------------------------------- +LICENCE +- - - - + Modified LGPL -- see the file COPYING.modifiedLGPL. + +----------------------------------------------------------- +NO WARRANTY +- - - - - - + There is no warranty whatsoever. + +----------------------------------------------------------- +BEST REGARDS TO LAZARUS COMMUNITY! +- - - - - - - - - - - - - - - - - - + I do hope the ZVDateTimeCtrls package will be useful. +} +unit ZVDateTimePickerPropEdit; + +{$mode objfpc}{$H+} + +interface +// Nothing needs to be in interface section! + +implementation + +uses + Classes, SysUtils, Forms, Controls, ButtonPanel, ZVDateTimePicker, + DBZVDateTimePicker, StdCtrls, Math, Menus, ComponentEditors, PropEdits; + +type + { TFormZVDateTimePickerEditor } + + TFormZVDateTimePickerEditor = class(TForm) + private + CallerZVDateTimePicker: TZVDateTimePicker; + Prop: String; + Modified: Boolean; + + ButtonPanel: TButtonPanel; + ZVDateTimePickerMin: TZVDateTimePicker; + ZVDateTimePicker1: TZVDateTimePicker; + ZVDateTimePickerMax: TZVDateTimePicker; + Label1: TLabel; + LabelMin: TLabel; + LabelMax: TLabel; + LabelNull: TLabel; + procedure ZVDateTimePickerMaxExit(Sender: TObject); + procedure ZVDateTimePickerMinExit(Sender: TObject); + procedure ZVDateTimePickersChange(Sender: TObject); + procedure ZVDateTimePicker1Enter(Sender: TObject); + procedure ZVDateTimePicker1Exit(Sender: TObject); + procedure FormActivate(Sender: TObject); + + procedure Initialize(const Caller: TZVDateTimePicker; + const PropertyName, PropertyType: String); + procedure UpdateMinMaxBounds; + public + constructor CreateNew(AOwner: TComponent; Num: Integer = 0); override; + destructor Destroy; override; + end; + + { TZVDateTimePickerComponentEditor } + + TZVDateTimePickerComponentEditor = class(TComponentEditor) + public + procedure ExecuteVerb(Index: Integer); override; + function GetVerb(Index: Integer): string; override; + function GetVerbCount: Integer; override; + end; + + { TZVDateTimePickerDateTimePropEditor } + + TZVDateTimePickerDateTimePropEditor = class(TDateTimePropertyEditor) + public + function GetAttributes: TPropertyAttributes; override; + function AllEqual: Boolean; override; + function GetValue: string; override; + procedure SetValue(const Value: string); override; + procedure Edit; override; + end; + + { TSimpleDatePropEditor } + + TSimpleDatePropEditor = class(TDatePropertyEditor) + public + function GetValue: string; override; + procedure SetValue(const Value: string); override; + end; + +procedure RegPropEdits; +begin + RegisterPropertyEditor(TypeInfo(TTime), TZVDateTimePicker, 'Time', TZVDateTimePickerDateTimePropEditor); + RegisterPropertyEditor(TypeInfo(TDate), TZVDateTimePicker, 'Date', TZVDateTimePickerDateTimePropEditor); + RegisterPropertyEditor(TypeInfo(TDate), TZVDateTimePicker, 'MaxDate', TZVDateTimePickerDateTimePropEditor); + RegisterPropertyEditor(TypeInfo(TDate), TZVDateTimePicker, 'MinDate', TZVDateTimePickerDateTimePropEditor); + RegisterPropertyEditor(TypeInfo(TDate), TDBZVDateTimePicker, 'MaxDate', TSimpleDatePropEditor); + RegisterPropertyEditor(TypeInfo(TDate), TDBZVDateTimePicker, 'MinDate', TSimpleDatePropEditor); +end; + +{ TZVDateTimePickerComponentEditor } + +procedure TZVDateTimePickerComponentEditor.ExecuteVerb(Index: Integer); +var + F: TFormZVDateTimePickerEditor; + DTPicker: TZVDateTimePicker; +begin + if Index = 0 then begin + if GetComponent is TZVDateTimePicker then begin + F := TFormZVDateTimePickerEditor.CreateNew(nil, 0); + try + DTPicker := TZVDateTimePicker(GetComponent); + if DTPicker.Kind = dtkTime then + F.Initialize(DTPicker, '', 'TTime') + else + F.Initialize(DTPicker, '', ''); + + if F.ShowModal = mrOK then begin + if F.Modified then begin + DTPicker.MinDate := TheSmallestDate; + DTPicker.MaxDate := F.ZVDateTimePickerMax.DateTime; + DTPicker.MinDate := F.ZVDateTimePickerMin.DateTime; + + DTPicker.DateTime := F.ZVDateTimePicker1.DateTime; + Modified; + GlobalDesignHook.RefreshPropertyValues; + end; + end; + finally + F.Free; + end; + end else + raise Exception.Create('Unknown ZVDateTimePicker object to edit.'); + end; +end; + +function TZVDateTimePickerComponentEditor.GetVerb(Index: Integer): string; +begin + if Index = 0 then + Result := '&Date/Time Editor...'; +end; + +function TZVDateTimePickerComponentEditor.GetVerbCount: Integer; +begin + Result := 1; +end; + +{ TFormZVDateTimePickerEditor } + +procedure TFormZVDateTimePickerEditor.ZVDateTimePickerMaxExit(Sender: TObject); +begin + if ZVDateTimePickerMin.Date > ZVDateTimePickerMax.Date then + ZVDateTimePickerMin.Date := ZVDateTimePickerMax.Date; + + UpdateMinMaxBounds; +end; + +procedure TFormZVDateTimePickerEditor.ZVDateTimePickerMinExit(Sender: TObject); +begin + if ZVDateTimePickerMax.Date < ZVDateTimePickerMin.Date then + ZVDateTimePickerMax.Date := ZVDateTimePickerMin.Date; + + UpdateMinMaxBounds; +end; + +procedure TFormZVDateTimePickerEditor.ZVDateTimePickersChange(Sender: TObject); +begin + Modified := True; +end; + +procedure TFormZVDateTimePickerEditor.ZVDateTimePicker1Enter(Sender: TObject); +begin + if ZVDateTimePicker1.NullInputAllowed then + LabelNull.Show; +end; + +procedure TFormZVDateTimePickerEditor.ZVDateTimePicker1Exit(Sender: TObject); +begin + LabelNull.Hide; +end; + +procedure TFormZVDateTimePickerEditor.FormActivate(Sender: TObject); +var + B: Boolean; +begin + OnActivate := nil; + B := False; + if Prop = 'MAXDATE' then ZVDateTimePickerMax.SetFocus + else if Prop = 'MINDATE' then ZVDateTimePickerMin.SetFocus + else begin + ZVDateTimePicker1.SetFocus; + B := ZVDateTimePicker1.NullInputAllowed; + end; + LabelNull.Visible := B; + LabelNull.BringToFront; +end; + +procedure TFormZVDateTimePickerEditor.Initialize(const Caller: TZVDateTimePicker; + const PropertyName, PropertyType: String); +var + I: Integer; + DTP: array[1..3] of TZVDateTimePicker; + + L, T, W, H: Integer; + R: TRect; +begin + if Assigned(Caller) then begin + CallerZVDateTimePicker := Caller; + Prop := UpperCase(PropertyName); + + Modified := False; + ZVDateTimePicker1.Kind := dtkDateTime; + if UpperCase(PropertyType) = 'TTIME' then + ZVDateTimePicker1.SelectTime + else + ZVDateTimePicker1.SelectDate; + + Label1.Caption := 'Date / Time:'; + LabelMax.Caption := 'MaxDate:'; + LabelMin.Caption := 'MinDate:'; + LabelNull.Caption := '(Press N to set to NULL)'; + + ZVDateTimePickerMin.DateTime := CallerZVDateTimePicker.MinDate; + ZVDateTimePickerMax.DateTime := CallerZVDateTimePicker.MaxDate; + ZVDateTimePicker1.MinDate := CallerZVDateTimePicker.MinDate; + ZVDateTimePicker1.MaxDate := CallerZVDateTimePicker.MaxDate; + ZVDateTimePicker1.DateTime := CallerZVDateTimePicker.DateTime; + + DTP[1] := ZVDateTimePickerMin; + DTP[2] := ZVDateTimePickerMax; + DTP[3] := ZVDateTimePicker1; + for I := 1 to 3 do begin + DTP[I].NullInputAllowed := I = 3; + DTP[I].CenturyFrom := CallerZVDateTimePicker.CenturyFrom; + DTP[I].DateDisplayOrder := CallerZVDateTimePicker.DateDisplayOrder; + DTP[I].LeadingZeros := CallerZVDateTimePicker.LeadingZeros; + DTP[I].DateSeparator := CallerZVDateTimePicker.DateSeparator; + DTP[I].TrailingSeparator := CallerZVDateTimePicker.TrailingSeparator; + end; + ZVDateTimePicker1.TextForNullDate := CallerZVDateTimePicker.TextForNullDate; + ZVDateTimePicker1.TimeSeparator := CallerZVDateTimePicker.TimeSeparator; + ZVDateTimePicker1.TimeDisplay := tdHMSMs; + ZVDateTimePicker1.TimeFormat := CallerZVDateTimePicker.TimeFormat; + + ZVDateTimePickerMax.AnchorParallel(akTop, 20, Self); + ZVDateTimePickerMax.AnchorParallel(akRight, 20, Self); + LabelMax.AnchorVerticalCenterTo(ZVDateTimePickerMax); + LabelMax.AnchorToNeighbour(akRight, 2, ZVDateTimePickerMax); + ZVDateTimePickerMin.AnchorParallel(akTop, 20, Self); + ZVDateTimePickerMin.AnchorToNeighbour(akRight, 20, LabelMax); + LabelMin.AnchorToNeighbour(akRight, 2, ZVDateTimePickerMin); + LabelMin.AnchorVerticalCenterTo(ZVDateTimePickerMin); + ZVDateTimePicker1.AnchorParallel(akLeft, 0, ZVDateTimePickerMin); + ZVDateTimePicker1.AnchorToNeighbour(akTop, 20, ZVDateTimePickerMin); + Label1.AnchorToNeighbour(akRight, 2, ZVDateTimePicker1); + Label1.AnchorVerticalCenterTo(ZVDateTimePicker1); + LabelNull.AnchorToNeighbour(akTop, 2, ZVDateTimePicker1); + LabelNull.AnchorHorizontalCenterTo(ZVDateTimePicker1); + + ButtonPanel.Spacing := 10; + ButtonPanel.BorderSpacing.Around := 10; + + W := Max(Label1.Width, LabelMin.Width); + + W := ZVDateTimePickerMax.Width + ZVDateTimePickerMin.Width + + LabelMax.Width + W + 80; + + H := 2 * ZVDateTimePickerMax.Height + LabelNull.Height + ButtonPanel.Height + 58; + + R := Screen.MonitorFromWindow(CallerZVDateTimePicker.Handle).WorkareaRect; + L := (R.Left + R.Right - W) div 2; + T := (R.Top + R.Bottom - H) div 2; + + if L < R.Left then L := R.Left; + if T < R.Top then T := R.Top; + + SetBounds(L, T, W, H); + end; + +end; + +procedure TFormZVDateTimePickerEditor.UpdateMinMaxBounds; +begin + ZVDateTimePicker1.MinDate := TheSmallestDate; + ZVDateTimePicker1.MaxDate := ZVDateTimePickerMax.Date; + ZVDateTimePicker1.MinDate := ZVDateTimePickerMin.Date; +end; + +constructor TFormZVDateTimePickerEditor.CreateNew(AOwner: TComponent; + Num: Integer); +var + I: Integer; +begin + inherited CreateNew(AOwner, Num); + + Hide; + if Font.Size > 10 then + Font.Size := 10; + + SetBounds(-8000, -8000, 4, 5); + BorderStyle := bsDialog; + BorderIcons := [biSystemMenu]; + Caption := 'ZVDateTimePicker Editor'; + + ZVDateTimePickerMax := TZVDateTimePicker.Create(Self); + ZVDateTimePickerMin := TZVDateTimePicker.Create(Self); + ZVDateTimePicker1 := TZVDateTimePicker.Create(Self); + Label1 := TLabel.Create(Self); + LabelMin := TLabel.Create(Self); + LabelMax := TLabel.Create(Self); + LabelNull := TLabel.Create(Self); + + ButtonPanel := TButtonPanel.Create(Self); + ButtonPanel.ShowButtons := [pbOK, pbCancel]; + ButtonPanel.OKButton.GlyphShowMode := gsmAlways; + ButtonPanel.CancelButton.GlyphShowMode := gsmAlways; + ButtonPanel.ShowBevel := False; + + ZVDateTimePickerMax.Parent := Self; + ZVDateTimePickerMin.Parent := Self; + ZVDateTimePicker1.Parent := Self; + Label1.Parent := Self; + LabelMin.Parent := Self; + LabelMax.Parent := Self; + LabelNull.Parent := Self; + ButtonPanel.Parent := Self; + + ButtonPanel.TabOrder := 0; + ZVDateTimePickerMin.TabOrder := 1; + ZVDateTimePickerMax.TabOrder := 2; + ZVDateTimePicker1.TabOrder := 3; + + for I := 0 to ControlCount - 1 do begin + Controls[I].Anchors := []; + Controls[I].AutoSize := True; + end; + + ZVDateTimePickerMax.OnExit := @ZVDateTimePickerMaxExit; + ZVDateTimePickerMin.OnExit := @ZVDateTimePickerMinExit; + ZVDateTimePicker1.OnExit := @ZVDateTimePicker1Exit; + ZVDateTimePicker1.OnEnter := @ZVDateTimePicker1Enter; + ZVDateTimePickerMin.OnChange := @ZVDateTimePickersChange; + ZVDateTimePickerMax.OnChange := @ZVDateTimePickersChange; + ZVDateTimePicker1.OnChange := @ZVDateTimePickersChange; + + OnActivate := @FormActivate; +end; + +destructor TFormZVDateTimePickerEditor.Destroy; +begin + OnActivate := nil; + OnShow := nil; + + ZVDateTimePicker1.OnChange := nil; + ZVDateTimePickerMax.OnChange := nil; + ZVDateTimePickerMin.OnChange := nil; + ZVDateTimePicker1.OnEnter := nil; + ZVDateTimePicker1.OnExit := nil; + ZVDateTimePickerMin.OnExit := nil; + ZVDateTimePickerMax.OnExit := nil; + + ButtonPanel.Free; + LabelNull.Free; + LabelMax.Free; + LabelMin.Free; + Label1.Free; + ZVDateTimePicker1.Free; + ZVDateTimePickerMin.Free; + ZVDateTimePickerMax.Free; + + inherited Destroy; +end; + +{ TZVDateTimePickerDateTimePropEditor } + +function TZVDateTimePickerDateTimePropEditor.GetAttributes: TPropertyAttributes; +begin + Result := inherited GetAttributes + [paDialog]; +end; + +function TZVDateTimePickerDateTimePropEditor.AllEqual: Boolean; +var + DT: TDateTime; + N: Integer; +begin + Result := True; + N := PropCount; + if N > 1 then begin + DT := TDateTime(GetFloatValue); + repeat + Dec(N); + Result := EqualDateTime(DT, TDateTime(GetFloatValueAt(N))); + until not(Result and (N > 1)); + end; +end; + +function TZVDateTimePickerDateTimePropEditor.GetValue: string; +var + DT: TDateTime; + S: String; +begin + DT := TDateTime(GetFloatValue); + if IsNullDate(DT) then + Result := 'NULL' + else begin + S := UpperCase(GetPropType^.Name); + if S = 'TDATE' then + Result := DateToStr(DT) + else if S = 'TTIME' then + Result := TimeToStr(DT) + else + Result := DateTimeToStr(DT); + end; +end; + +procedure TZVDateTimePickerDateTimePropEditor.SetValue(const Value: string); +var + S: String; +begin + S := Trim(Value); + if (S > '') and (UpCase(S[1]) <> 'N') then begin + S := UpperCase(GetPropType^.Name); + if S = 'TDATE' then + SetFloatValue(StrToDate(Value)) + else if S = 'TTIME' then + SetFloatValue(StrToTime(Value)) + else + inherited SetValue(Value); + end else + SetFloatValue(NullDate); +end; + +procedure TZVDateTimePickerDateTimePropEditor.Edit; +var + F: TFormZVDateTimePickerEditor; + I: Integer; + DT: TZVDateTimePicker; +begin + for I := 0 to PropCount - 1 do + if not (GetComponent(I) is TZVDateTimePicker) then + Exit; + + F := TFormZVDateTimePickerEditor.CreateNew(nil, 0); + try + F.Initialize(TZVDateTimePicker(GetComponent(0)), GetName, GetPropType^.Name); + if F.ShowModal = mrOK then begin + if F.Modified then begin + for I := 0 to PropCount - 1 do begin + DT := TZVDateTimePicker(GetComponent(I)); + DT.MinDate := TheSmallestDate; + DT.MaxDate := F.ZVDateTimePickerMax.Date; + DT.MinDate := F.ZVDateTimePickerMin.Date; + + DT.DateTime := F.ZVDateTimePicker1.DateTime; + end; + + Modified; + GlobalDesignHook.RefreshPropertyValues; + end; + end; + finally + F.Free; + end; +end; + +{ TSimpleDatePropEditor } + +function TSimpleDatePropEditor.GetValue: string; +begin + Result := DateToStr(GetFloatValue); +end; + +procedure TSimpleDatePropEditor.SetValue(const Value: string); +var + S: String; +begin + S := Trim(Value); + if (S > '') and (UpCase(S[1]) <> 'N') then + inherited SetValue(S); +end; + +initialization + RegPropEdits; + RegisterComponentEditor(TZVDateTimePicker, TZVDateTimePickerComponentEditor); + +end.