From fe114b6b49787ab20865352a31da4e5c2d983bbb Mon Sep 17 00:00:00 2001 From: zoran-vucenovic Date: Mon, 16 Jun 2014 11:33:49 +0000 Subject: [PATCH] Releasing the version 1.5 git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3172 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../ZVDateTimeCtrls/tags/1.5/COPYING.LGPL | 481 +++ .../tags/1.5/COPYING.modifiedLGPL | 28 + .../ZVDateTimeCtrls/tags/1.5/ChangeLog.txt | 81 + .../tags/1.5/calendarcontrolwrapper.pas | 103 + .../tags/1.5/dbzvdatetimepicker.pas | 289 ++ .../tags/1.5/lclcalendarwrapper.pas | 74 + .../ZVDateTimeCtrls/tags/1.5/manual.htm | 537 +++ .../tags/1.5/pictures/TDBZVDateTimePicker.png | Bin 0 -> 443 bytes .../tags/1.5/pictures/TZVDateTimePicker.png | Bin 0 -> 353 bytes .../tags/1.5/pictures/ZVDateControls01.PNG | Bin 0 -> 1543 bytes .../tags/1.5/pictures/ZVDateControls02.PNG | Bin 0 -> 1009 bytes .../tags/1.5/pictures/ZVDateControls03.PNG | Bin 0 -> 1492 bytes .../1.5/pictures/ZVDateTimePickerEditor.PNG | Bin 0 -> 10848 bytes .../ZVDateTimeCtrls/tags/1.5/readme.txt | 14 + .../tags/1.5/zvdatetimecontrolsreg.pas | 49 + .../tags/1.5/zvdatetimectrls.lpk | 85 + .../tags/1.5/zvdatetimectrls.lrs | 33 + .../tags/1.5/zvdatetimectrls.pas | 23 + .../tags/1.5/zvdatetimepicker.pas | 3686 +++++++++++++++++ .../tags/1.5/zvdatetimepickerpropedit.pas | 513 +++ 20 files changed, 5996 insertions(+) create mode 100644 components/ZVDateTimeCtrls/tags/1.5/COPYING.LGPL create mode 100644 components/ZVDateTimeCtrls/tags/1.5/COPYING.modifiedLGPL create mode 100644 components/ZVDateTimeCtrls/tags/1.5/ChangeLog.txt create mode 100644 components/ZVDateTimeCtrls/tags/1.5/calendarcontrolwrapper.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/dbzvdatetimepicker.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/lclcalendarwrapper.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/manual.htm create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/TDBZVDateTimePicker.png create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/TZVDateTimePicker.png create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/ZVDateControls01.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/ZVDateControls02.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/ZVDateControls03.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.5/pictures/ZVDateTimePickerEditor.PNG create mode 100644 components/ZVDateTimeCtrls/tags/1.5/readme.txt create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimecontrolsreg.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.lpk create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.lrs create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimepicker.pas create mode 100644 components/ZVDateTimeCtrls/tags/1.5/zvdatetimepickerpropedit.pas diff --git a/components/ZVDateTimeCtrls/tags/1.5/COPYING.LGPL b/components/ZVDateTimeCtrls/tags/1.5/COPYING.LGPL new file mode 100644 index 000000000..5bc8fb2c8 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/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.5/COPYING.modifiedLGPL b/components/ZVDateTimeCtrls/tags/1.5/COPYING.modifiedLGPL new file mode 100644 index 000000000..d576c67c3 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/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.5/ChangeLog.txt b/components/ZVDateTimeCtrls/tags/1.5/ChangeLog.txt new file mode 100644 index 000000000..431851cbb --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/ChangeLog.txt @@ -0,0 +1,81 @@ +=================================================== +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... + +=================================================== + +Version 1.5 -- 16. June 2014. + +These are main changes: + + New properties added: AutoAdvance, Cascade, AutoButtonSize, HideDateTimeParts, CalendarWrapperClass (public), ShowMonthNames, MonthNames. + + Showing month names instead of numbers is possible now, with new properties ShowMonthNames and MonthNames. + + Now possible to use some other calendar control instead of LCL's TCalendar, with CalendarWrapperClass property. + diff --git a/components/ZVDateTimeCtrls/tags/1.5/calendarcontrolwrapper.pas b/components/ZVDateTimeCtrls/tags/1.5/calendarcontrolwrapper.pas new file mode 100644 index 000000000..8713f4e8a --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/calendarcontrolwrapper.pas @@ -0,0 +1,103 @@ +{ +CalendarControlWrapper +- - - - - - - - - - - - - - - - - +Author: Zoran Vučenović + Зоран Вученовић + + This unit is part of ZVDateTimeCtrls package for Lazarus. + + By default, TZVDateTimePicker uses LCL's TCalendar to represent the +drop-down calendar, but you can use some other calendar control instead. + + In order to use another calendar control, you should "wrap" that control with +a CalendarControlWrapper. + + To be used by ZVDateTimePicker, the calendar control must at least provide +a way to determine whether the coordinates are on the date (when this control +gets clicked, we must decide if the date has just been chosen - then we should +respond by closing the drop-down form and setting the date from calendar to +ZVDateTimePicker - for example in LCL's TCalendar we will respond when the +calendar is clicked on date, but not when the user clicks in title area changing +months or years, then we let the user keep browsing the calendar). + + When creating new wrapper, there are four abstract methods which need to be +overriden. Please see the coments in code below. + +----------------------------------------------------------- +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 CalendarControlWrapper; + +{$mode objfpc}{$H+} + +interface + +uses + Controls; + +type + + { TCalendarControlWrapper } + + TCalendarControlWrapper = class + private + FCalendarControl: TControl; + public + { There are four methods that derived classes should override: } + + { Should be overriden to just return the class of the calendar control. } + class function GetCalendarControlClass: TControlClass; virtual abstract; + + { Should be overriden to set the date in the calendar control. } + procedure SetDate(Date: TDate); virtual abstract; + + { Should be overriden to get the date from the calendar control. } + function GetDate: TDate; virtual abstract; + + { This function should return True if coordinates (X, Y) are on the date in + the calendar control (ZVDateTimePicker calls this function when the calendar + is clicked, to determine whether the drop-down calendar should return the + date or not). } + function AreCoordinatesOnDate(X, Y: Integer): Boolean; virtual abstract; + + function GetCalendarControl: TControl; + constructor Create; virtual; + destructor Destroy; override; + end; + + TCalendarControlWrapperClass = class of TCalendarControlWrapper; + +implementation + +{ TCalendarControlWrapper } + +function TCalendarControlWrapper.GetCalendarControl: TControl; +begin + Result := FCalendarControl; +end; + +constructor TCalendarControlWrapper.Create; +begin + FCalendarControl := GetCalendarControlClass.Create(nil); +end; + +destructor TCalendarControlWrapper.Destroy; +begin + FCalendarControl.Free; + inherited Destroy; +end; + +end. + diff --git a/components/ZVDateTimeCtrls/tags/1.5/dbzvdatetimepicker.pas b/components/ZVDateTimeCtrls/tags/1.5/dbzvdatetimepicker.pas new file mode 100644 index 000000000..62b6a6db4 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/dbzvdatetimepicker.pas @@ -0,0 +1,289 @@ +{ +TDBZVDateTimePicker control for Lazarus +- - - - - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + +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; + property CalendarWrapperClass; + 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; + property Cascade; + property AutoButtonSize; + property AutoAdvance; + property HideDateTimeParts; + property BiDiMode; + property ParentBiDiMode; + property MonthNames; + property ShowMonthNames; + //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.5/lclcalendarwrapper.pas b/components/ZVDateTimeCtrls/tags/1.5/lclcalendarwrapper.pas new file mode 100644 index 000000000..824980528 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/lclcalendarwrapper.pas @@ -0,0 +1,74 @@ +{ +LCLCalendarWrapper +- - - - - - - - - - - - - - - - - +Author: Zoran Vučenović + Зоран Вученовић + + This unit is part of ZVDateTimeCtrls package for Lazarus. + + TLCLCalendarWrapper is the default implementation of TCalendarControlWrapper +abstract class, used by ZVDateTimePicker. Wraps LCL's TCalendar. + +----------------------------------------------------------- +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 LCLCalendarWrapper; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, Controls, Calendar, CalendarControlWrapper; + +type + + { TLCLCalendarWrapper } + + TLCLCalendarWrapper = class(TCalendarControlWrapper) + public + class function GetCalendarControlClass: TControlClass; override; + procedure SetDate(Date: TDate); override; + function GetDate: TDate; override; + function AreCoordinatesOnDate(X, Y: Integer): Boolean; override; + end; + +implementation + +{ TLCLCalendarWrapper } + +class function TLCLCalendarWrapper.GetCalendarControlClass: TControlClass; +begin + Result := TCalendar; +end; + +procedure TLCLCalendarWrapper.SetDate(Date: TDate); +begin + TCalendar(GetCalendarControl).DateTime := Date; +end; + +function TLCLCalendarWrapper.GetDate: TDate; +begin + Result := TCalendar(GetCalendarControl).DateTime; +end; + +function TLCLCalendarWrapper.AreCoordinatesOnDate(X, Y: Integer): Boolean; +begin + Result := + TCalendar(GetCalendarControl).HitTest(Point(X, Y)) in [cpDate, cpNoWhere]; +end; + +end. + diff --git a/components/ZVDateTimeCtrls/tags/1.5/manual.htm b/components/ZVDateTimeCtrls/tags/1.5/manual.htm new file mode 100644 index 000000000..299f80291 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/manual.htm @@ -0,0 +1,537 @@ + + + + + + + + + + + + + +

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.

+

+Version 1.5 – 16. June 2014.

+


+

+

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 achieved by +setting TextForNullDate to one or more space characters.

+


+

+

+AutoAdvance: Boolean

+

+When true, then when user is entering +valid text, the selection automatically advances to next part of +date/time. The default is False because of compatibility with +previous version, but switching on this option makes user interaction +easier, this is a useful option and I recommend setting this property +to true.

+


+

+

+Cascade: Boolean

+

+When true, then when user is +increasing or decreasing one date/time part (using up-down keys or +mouse wheel), it can increase or decrease by one another date/time +part. For example, when date is 31.08.2013. and user increases the +day, the day becomes 1 and month increases by one and becomes 9, so +the date becomes 01.09.2013. If Cascade were set to False, the month +would not change and the date would become 01.08.2013.

+


+

+

+AutoButtonSize: Boolean

+

+When true, the width of the arrow +button (or up-down control, if it is shown instead) is automatically +adjusted proportionally to the height.

+


+

+

+HideDateTimeParts: TDateTimeParts

+

+type

+

+TDateTimePart = (dtpDay, +dtpMonth, dtpYear, dtpHour, dtpMinute, dtpSecond, dtpMiliSec, +dtpAMPM);

+

+TDateTimeParts = set of +dtpDay..dtpMiliSec;

+

+With +HideDateTimeParts property, +you can chose which date/time parts will not be shown. Most of the +time you do not need to use this property and you can get the format +you want by using other properties (see Kind, +TimeDisplay). However, if +you need more control (for example, you might want to let user edit +only days, months and hours), you can additionally hide any date/time +parts with this control. Keep in mind that, with this property, you +cannot show any date/time part which is hidden by another property +(for example, if TimeDisplay is tdHM, the second part is not shown, +regardless of this property).

+


+

+

+CalendarWrapperClass: +TCalendarControlWrapperClass (public)

+

+When assigned, this property +determines the type of the calendar control used for drop-down +calendar. When set to nil, which is the default, the value of global +variable DefaultCalendarWrapperClass is used.

+


+

+

+ShowMonthNames: Boolean

+

+When this property +is set to True, month names, set in MonthNames +property, will be displayed instead of numbers.

+


+

+

+MonthNames: +String

+

+When ShowMonthNames +is set to True, this property determines which month names should +appear. If MonthNames is set to 'Short' or 'Long', then month names +are set to ShortMonthNames +or LongMonthNames +respectively. To set the month names explicitly, this property should +be set to string which starts with a character which will be used to +separate months and then twelve names separated by this character. +For example ',I,II,III,IV,V,VI,VII,VIII,IX,X,XI,XII' — roman +numbers are used for months — the first character is comma, which +means that comma is used to separate the months. Another valid +example ';jan;feb;mar;apr;maj;jun;jul;avg;sep;okt;nov;dec'. So, the +separator should be the first character, before the first month name, +and then only if there are twelve month names separated by that +separator, the format is valid. The default value of this property is +'Long'.

+


+

+

+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 +ellipsis (…) 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.5/pictures/TDBZVDateTimePicker.png b/components/ZVDateTimeCtrls/tags/1.5/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.5/pictures/TZVDateTimePicker.png b/components/ZVDateTimeCtrls/tags/1.5/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.5/pictures/ZVDateControls01.PNG b/components/ZVDateTimeCtrls/tags/1.5/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.5/pictures/ZVDateControls03.PNG b/components/ZVDateTimeCtrls/tags/1.5/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.5/zvdatetimectrls.lrs b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.lrs new file mode 100644 index 000000000..1c4b665d4 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/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.5/zvdatetimectrls.pas b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.pas new file mode 100644 index 000000000..652ce8bb0 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimectrls.pas @@ -0,0 +1,23 @@ +{ 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, CalendarControlWrapper, LCLCalendarWrapper, + LazarusPackageIntf; + +implementation + +procedure Register; +begin + RegisterUnit('ZVDateTimeControlsReg', @ZVDateTimeControlsReg.Register); +end; + +initialization + RegisterPackage('ZVDateTimeCtrls', @Register); +end. diff --git a/components/ZVDateTimeCtrls/tags/1.5/zvdatetimepicker.pas b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimepicker.pas new file mode 100644 index 000000000..a0c139df5 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimepicker.pas @@ -0,0 +1,3686 @@ +{ +TZVDateTimePicker control for Lazarus +- - - - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + + 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 locale settings on Linux. + {$endif} + Classes, SysUtils, Controls, LCLType, Graphics, Math, StdCtrls, Buttons, + ExtCtrls, Forms, ComCtrls, Types, LMessages, LazUTF8, CalendarControlWrapper, + LCLVersion; + +const +{ With future Lazarus 1.4, use DateTimeCtrls package: } +{$if lcl_fullversion >= 01040000} +{$Hint From Lazarus version 1.4, package ZVDateTimeCtrls should be replaced by + package DateTimeCtrls, which is included in Lazarus distribution.} +{$endif} + + { 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. + +var + DefaultCalendarWrapperClass: TCalendarControlWrapperClass = nil; + +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 + AdjustEffectiveHideDateTimeParts procedure } + TDateDisplayOrder = (ddoDMY, ddoMDY, ddoYMD, ddoTryDefault); + + 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); + + TTextPart = 1..8; + TDateTimePart = (dtpDay, dtpMonth, dtpYear, dtpHour, dtpMinute, + dtpSecond, dtpMiliSec, dtpAMPM); + TDateTimeParts = set of dtpDay..dtpMiliSec; // without AMPM, + // because this set type is used for HideDateTimeParts property, + // where hiding of AMPM part is tied to hiding of hour (and, of + // course, it makes a difference only when TimeFormat is set to tf12) + + TArrowShape = (asClassicSmaller, asClassicLarger, asModernSmaller, + asModernLarger, asYetAnotherShape); + + TDTDateMode = (dmComboBox, dmUpDown, dmNone); + + { TCustomZVDateTimePicker } + + TCustomZVDateTimePicker = class(TCustomControl) + private + FAutoAdvance: Boolean; + FAutoButtonSize: Boolean; + FCalendarWrapperClass: TCalendarControlWrapperClass; + FCascade: Boolean; + FCenturyFrom, FEffectiveCenturyFrom: Word; + FDateDisplayOrder: TDateDisplayOrder; + FHideDateTimeParts: TDateTimeParts; + FEffectiveHideDateTimeParts: set of TDateTimePart; + FKind: TDateTimeKind; + FLeadingZeros: Boolean; + FMonthNames: String; + FMonthNamesArray: TMonthNameArray; + FNullInputAllowed: Boolean; + FDateTime: TDateTime; + FDateSeparator: String; + FReadOnly: Boolean; + FMaxDate, FMinDate: TDate; + FShowMonthNames: Boolean; + FTextForNullDate: String; + FTimeSeparator: String; + FTimeDisplay: TTimeDisplay; + FTimeFormat: TTimeFormat; + FTrailingSeparator: Boolean; + FUseDefaultSeparators: Boolean; + FUserChangedText: Boolean; + FYearPos, FDayPos, FMonthPos: 1..3; + FTextPart: array[1..3] of String; + FTimeText: array[dtpHour..dtpAMPM] of String; + FUserChanging: Integer; + FDigitWidth: Integer; + FTextHeight: Integer; + FSeparatorWidth: Integer; + FSepNoSpaceWidth: Integer; + FTimeSeparatorWidth: Integer; + FMonthWidth: Integer; + FNullMonthText: String; + FSelectedTextPart: TTextPart; + 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; + FChangeInRecursiveCall: 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 SetAutoButtonSize(AValue: Boolean); + procedure SetCalendarWrapperClass(AValue: TCalendarControlWrapperClass); + procedure SetCenturyFrom(const AValue: Word); + procedure SetChecked(const AValue: Boolean); + procedure CheckTextEnabled; + procedure SetDateDisplayOrder(const AValue: TDateDisplayOrder); + procedure SetDateMode(const AValue: TDTDateMode); + procedure SetHideDateTimeParts(AValue: TDateTimeParts); + procedure SetKind(const AValue: TDateTimeKind); + procedure SetLeadingZeros(const AValue: Boolean); + procedure SetMonthNames(AValue: String); + 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 SetShowMonthNames(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 AdjustEffectiveHideDateTimeParts; + procedure SelectDateTimePart(const DateTimePart: TDateTimePart); + procedure MoveSelectionLR(const ToLeft: Boolean); + procedure DestroyCalendarForm; + procedure DropDownCalendarForm; + procedure UpdateShowArrowButton; + 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; + procedure AutoResizeButton; + + protected + procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS; + procedure WMSize(var Message: TLMSize); message LM_SIZE; + + class function GetControlClassDefaultSize: TSize; override; + + procedure ConfirmChanges; virtual; + procedure UndoChanges; virtual; + + function GetDateTimePartFromTextPart(TextPart: TTextPart): TDateTimePart; + function GetSelectedDateTimePart: TDateTimePart; + procedure FontChanged(Sender: TObject); override; + function GetTextOrigin(IgnoreRightToLeft: Boolean = False): 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 SetBiDiMode(AValue: TBiDiMode); 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; + property Cascade: Boolean read FCascade write FCascade default False; + property AutoButtonSize: Boolean + read FAutoButtonSize write SetAutoButtonSize default False; + property AutoAdvance: Boolean + read FAutoAdvance write FAutoAdvance default True; + property HideDateTimeParts: TDateTimeParts + read FHideDateTimeParts write SetHideDateTimeParts; + property CalendarWrapperClass: TCalendarControlWrapperClass + read FCalendarWrapperClass write SetCalendarWrapperClass; + property MonthNames: String read FMonthNames write SetMonthNames; + property ShowMonthNames: Boolean + read FShowMonthNames write SetShowMonthNames default False; + + 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; + property CalendarWrapperClass; + 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; + property Cascade; + property AutoButtonSize; + property AutoAdvance; + property HideDateTimeParts; + property BiDiMode; + property ParentBiDiMode; + property MonthNames; + property ShowMonthNames; +// 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 + +uses + DateUtils, LCLCalendarWrapper; + +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; + +type + + { TDTCalendarForm } + + TDTCalendarForm = class(TForm) + private + DTPicker: TCustomZVDateTimePicker; + Cal: TCalendarControlWrapper; + 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); + + protected + procedure Deactivate; override; + procedure DoShow; override; + procedure DoClose(var CloseAction: TCloseAction); override; + procedure Notification(AComponent: TComponent; Operation: TOperation); override; + + public + constructor CreateNewDTCalendarForm(AOwner: TComponent; + ADTPicker: TCustomZVDateTimePicker); + destructor Destroy; override; + published + end; + +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.GetCalendarControl.Width + 2; + ClientHeight := Cal.GetCalendarControl.Height + 2; + + Shape.SetBounds(0, 0, ClientWidth, ClientHeight); + + AdjustCalendarFormScreenPosition; + + end; +end; + +procedure TDTCalendarForm.AdjustCalendarFormScreenPosition; +var + M: TMonitor; + R: TRect; + P: TPoint; + H, W: Integer; +begin + H := Height; + W := Width; + + if IsRightToLeft then + P := DTPicker.ControlToScreen(Point(DTPicker.Width - W, DTPicker.Height)) + else + P := DTPicker.ControlToScreen(Point(0, DTPicker.Height)); + + M := Screen.MonitorFromWindow(DTPicker.Handle); + + R := M.WorkareaRect; + // WorkareaRect sometimes is not implemented (gtk2?). Depends on widgetset + // and window manager or something like that. Then it returns (0,0,0,0) and + // the best we can do is use BoundsRect instead: + if (R.Right <= R.Left) or (R.Bottom <= R.Top) then + R := M.BoundsRect; + + 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 + try + SetClosingCalendarForm; + Visible := False; + + 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.GetDate)); + end else if not EqualDateTime(Int(DTPicker.DateTime), + Int(Cal.GetDate)) then begin + // we'll change the date, but keep the time: + DTPicker.SetDateTime(ComposeDateTime(Cal.GetDate, DTPicker.DateTime)); + end; + finally + Dec(DTPicker.FUserChanging); + end; + end; + + if Screen.ActiveCustomForm = Self then + DTPicker.SetFocusIfPossible; + + DTPicker.DoCloseUp; + end; + + finally + Release; + 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.AreCoordinatesOnDate(X, Y) 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; + +type + { To be able to access TControl's protected members, + we derive our class TDTControl from TControl: } + TDTControl = class(TControl); + +constructor TDTCalendarForm.CreateNewDTCalendarForm(AOwner: TComponent; + ADTPicker: TCustomZVDateTimePicker); +var + P: TPoint; + CalClass: TCalendarControlWrapperClass; +begin + inherited CreateNew(AOwner); + + ADTPicker.FAllowDroppingCalendar := False; + FClosing := False; + + DTPicker := ADTPicker; + BiDiMode := DTPicker.BiDiMode; + DTPickersParentForm := GetParentForm(DTPicker); + if Assigned(DTPickersParentForm) then begin + DTPickersParentForm.AddHandlerOnVisibleChanged(@VisibleOfParentChanged); + DTPickersParentForm.FreeNotification(Self); + end; + PopupMode := pmAuto; + + P := Point(0, 0); + + if ADTPicker.FCalendarWrapperClass = nil then begin + if DefaultCalendarWrapperClass = nil then + CalClass := TLCLCalendarWrapper + else + CalClass := DefaultCalendarWrapperClass; + end else + CalClass := ADTPicker.FCalendarWrapperClass; + + Cal := CalClass.Create; + + Cal.GetCalendarControl.ParentBiDiMode := True; + Cal.GetCalendarControl.AutoSize := True; + Cal.GetCalendarControl.GetPreferredSize(P.x, P.y); + Cal.GetCalendarControl.Align := alNone; + Cal.GetCalendarControl.SetBounds(1, 1, P.x, P.y); + + 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.SetDate(Max(DTPicker.MinDate, Min(SysUtils.Date, DTPicker.MaxDate))) + + else if DTPicker.DateTime < DTPicker.MinDate then // These "out of bounds" values + Cal.SetDate(DTPicker.MinDate) // can happen when DateTime was set with + else if DTPicker.DateTime > DTPicker.MaxDate then // "SetDateTimeJumpMinMax" protected + Cal.SetDate(DTPicker.MaxDate) // procedure (used in TDBZVDateTimePicker control). + + else + Cal.SetDate(DTPicker.Date); + + Cal.GetCalendarControl.OnResize := @CalendarResize; + TDTControl(Cal.GetCalendarControl).OnMouseUp := @CalendarMouseUp; + if Cal.GetCalendarControl is TWinControl then begin + TWinControl(Cal.GetCalendarControl).OnKeyDown := @CalendarKeyDown; + TWinControl(Cal.GetCalendarControl).TabStop := True; + TWinControl(Cal.GetCalendarControl).SetFocus; + end; + + Shape.Parent := Self; + Cal.GetCalendarControl.Parent := Self; + Cal.GetCalendarControl.BringToFront; +end; + +destructor TDTCalendarForm.Destroy; +begin + SetClosingCalendarForm; + if Assigned(DTPickersParentForm) then + DTPickersParentForm.RemoveAllHandlersOfObject(Self); + + if Assigned(Cal) then begin + Cal.GetCalendarControl.OnResize := nil; + TDTControl(Cal.GetCalendarControl).OnMouseUp := nil; + if Cal.GetCalendarControl is TWinControl then + TWinControl(Cal.GetCalendarControl).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; + +{ TCustomZVDateTimePicker } + +procedure TCustomZVDateTimePicker.SetChecked(const AValue: Boolean); +begin + if Assigned(FCheckBox) then + FCheckBox.Checked := AValue; + + CheckTextEnabled; + Invalidate; +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 + FDateMode := AValue; + UpdateShowArrowButton; +end; + +procedure TCustomZVDateTimePicker.SetHideDateTimeParts(AValue: TDateTimeParts); +begin + if FHideDateTimeParts <> AValue then begin + FHideDateTimeParts := AValue; + AdjustEffectiveHideDateTimeParts; + end; +end; + +procedure TCustomZVDateTimePicker.SetKind(const AValue: TDateTimeKind); +begin + if FKind <> AValue then begin + FKind := AValue; + AdjustEffectiveHideDateTimeParts; + end; +end; + +procedure TCustomZVDateTimePicker.SetLeadingZeros(const AValue: Boolean); +begin + if FLeadingZeros = AValue then Exit; + + FLeadingZeros := AValue; + UpdateDate; +end; + +procedure TCustomZVDateTimePicker.SetMonthNames(AValue: String); +var + I, N, LenMNSep: Integer; + MonthNamesSeparator: String; + +begin + if FMonthNames <> AValue then begin + AValue := TrimRight(AValue); + FMonthNames := AValue; + + if UpperCase(AValue) = 'SHORT' then + for I := Low(TMonthNameArray) to High(TMonthNameArray) do + FMonthNamesArray[I] := AnsiToUtf8(DefaultFormatSettings.ShortMonthNames[I]) + else begin + N := 0; + if Length(AValue) >= 24 then begin + MonthNamesSeparator := UTF8Copy(AValue, 1, 1); + LenMNSep := Length(MonthNamesSeparator); + if LenMNSep > 0 then begin + Delete(AValue, 1, LenMNSep); + + while N < 12 do begin + I := Pos(MonthNamesSeparator, AValue); + if I <= 1 then begin + if (I = 0) and (N = 11) and (Length(AValue) > 0) then begin + Inc(N); + FMonthNamesArray[N] := AValue; + end; + + Break; + end; + + Inc(N); + Dec(I); + FMonthNamesArray[N] := Copy(AValue, 1, I); + Delete(AValue, 1, I + LenMNSep); + end; + + end; + end; + + if N < 12 then + for I := Low(TMonthNameArray) to High(TMonthNameArray) do + FMonthNamesArray[I] := AnsiToUtf8(DefaultFormatSettings.LongMonthNames[I]); + end; + + if FShowMonthNames and + not (dtpMonth in FEffectiveHideDateTimeParts) then begin + FRecalculatingTextSizesNeeded := True; + UpdateDate; + end; + end; +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; + + FCheckBox.OnChange := @CheckBoxChange; + end else begin + FCheckBox.OnChange := nil; + FreeAndNil(FCheckBox); + + end; + ArrangeCtrls; + + finally + EnableAlign; + end; + end; +end; + +procedure TCustomZVDateTimePicker.SetShowMonthNames(AValue: Boolean); +begin + if FShowMonthNames <> AValue then begin + FShowMonthNames := AValue; + if not (dtpMonth in FEffectiveHideDateTimeParts) then begin + FRecalculatingTextSizesNeeded := True; + UpdateDate; + 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; + AdjustEffectiveHideDateTimeParts; + end; +end; + +procedure TCustomZVDateTimePicker.SetTimeFormat(const AValue: TTimeFormat); +begin + if FTimeFormat <> AValue then begin + FTimeFormat := AValue; + AdjustEffectiveHideDateTimeParts; + 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; +const + NullMonthChar = 'x'; +var + C: Char; + N, J: Integer; + S: String; + I: TDateTimePart; + DateParts, TimeParts: Integer; +begin + if HandleAllocated and 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; + + DateParts := 0; + FSepNoSpaceWidth := 0; + FSeparatorWidth := 0; + FMonthWidth := 0; + FDateWidth := 0; + FNullMonthText := ''; + S := ''; + if FKind in [dtkDate, dtkDateTime] then begin + + for I := dtpDay to dtpYear do + if not (I in FEffectiveHideDateTimeParts) then begin + Inc(DateParts); + if I = dtpYear then begin + FDateWidth := FDateWidth + 4 * FDigitWidth; + end else if (I = dtpMonth) and FShowMonthNames then begin + FMonthWidth := FDigitWidth; // Minimal MonthWidth is DigitWidth. + for J := Low(TMonthNameArray) to High(TMonthNameArray) do begin + N := Canvas.GetTextWidth(FMonthNamesArray[J]); + if N > FMonthWidth then + FMonthWidth := N; + end; + + N := Canvas.GetTextWidth(NullMonthChar); + if N > 0 then begin + N := FMonthWidth div N - 1; + if N > 1 then + FNullMonthText := StringOfChar(NullMonthChar, N); + end; + if N <= 1 then + FNullMonthText := NullMonthChar; + + FDateWidth := FDateWidth + FMonthWidth; + end else + FDateWidth := FDateWidth + 2 * FDigitWidth; + + end; + + if DateParts > 0 then begin + if FTrailingSeparator then begin + FSepNoSpaceWidth := Canvas.GetTextWidth(TrimRight(FDateSeparator)); + Inc(FDateWidth, FSepNoSpaceWidth); + end; + + if DateParts > 1 then begin + FSeparatorWidth := Canvas.GetTextWidth(FDateSeparator); + S := FDateSeparator; + + FDateWidth := FDateWidth + (DateParts - 1) * FSeparatorWidth; + end; + end; + + end; + + TimeParts := 0; + FTimeWidth := 0; + FAMPMWidth := 0; + FTimeSeparatorWidth := 0; + if FKind in [dtkTime, dtkDateTime] then begin + + for I := dtpHour to dtpMiliSec do + if not (I in FEffectiveHideDateTimeParts) then begin + Inc(TimeParts); + if TimeParts > 1 then + Inc(FTimeWidth, FTimeSeparatorWidth); + + if I = dtpMiliSec then + FTimeWidth := FTimeWidth + 3 * FDigitWidth + else + FTimeWidth := FTimeWidth + 2 * FDigitWidth; + + end; + + if TimeParts > 1 then begin + FTimeSeparatorWidth := Canvas.GetTextWidth(FTimeSeparator); + S := S + FTimeSeparator; + FTimeWidth := FTimeWidth + (TimeParts - 1) * FTimeSeparatorWidth; + end; + + if not (dtpAMPM in FEffectiveHideDateTimeParts) then begin + S := S + 'APM'; + FAMPMWidth := Max(Canvas.TextWidth('AM'), Canvas.TextWidth('PM')); + FTimeWidth := FTimeWidth + FDigitWidth + FAMPMWidth; + end; + + end; + + FTextWidth := FDateWidth + FTimeWidth; + if (DateParts > 0) and (TimeParts > 0) then + FTextWidth := FTextWidth + 2 * FDigitWidth; + + 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 + W := GetHour; + if upCase(S[1]) = '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 GetSelectedDateTimePart 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); + + dtpHour: + 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; + dtpMinute: + SetMinute(W); + dtpSecond: + SetSecond(W); + dtpMiliSec: + SetMiliSec(W); + + end; + + end; + finally + Dec(FUserChanging); + end; + end; +end; + +function TCustomZVDateTimePicker.GetSelectedText: String; +begin + if FSelectedTextPart <= 3 then + Result := FTextPart[FSelectedTextPart] + else + Result := FTimeText[TDateTimePart(FSelectedTextPart - 1)]; +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, J, Le: Integer; + InQuoteChar: Char; +begin + if FDateDisplayOrder = ddoTryDefault then begin + S := DefaultFormatSettings.ShortDateFormat; + FEffectiveDateDisplayOrder := ddoTryDefault; + + repeat + InQuoteChar := Chr(0); + Le := Length(S); + + I := 0; + while I < Le do begin + Inc(I); + if InQuoteChar = Chr(0) then begin + case S[I] of + '''', '"': + InQuoteChar := S[I]; + 'D', 'd': + begin + { If 3 or more "d"-s are standing together, then it's day + of week, but here we are interested in day of month. + So, we have to see what is following: } + J := I + 1; + while (J <= Le) and (upCase(S[J]) = 'D') do + Inc(J); + + if J <= I + 2 then begin + FEffectiveDateDisplayOrder := ddoDMY; + Break; + end; + + I := J - 1; + end; + 'M', 'm': + begin + FEffectiveDateDisplayOrder := ddoMDY; + Break; + end; + 'Y', 'y': + begin + FEffectiveDateDisplayOrder := ddoYMD; + Break; + end; + end; + end else + if S[I] = InQuoteChar then + InQuoteChar := Chr(0); + + 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; + + case FEffectiveDateDisplayOrder of + ddoDMY: + begin + FDayPos := 1; + FMonthPos := 2; + FYearPos := 3; + end; + ddoMDY: + begin + FDayPos := 2; + FMonthPos := 1; + FYearPos := 3; + end; + ddoYMD: + begin + FDayPos := 3; + FMonthPos := 2; + FYearPos := 1; + end; + end; + +end; + +procedure TCustomZVDateTimePicker.AdjustEffectiveHideDateTimeParts; +var + I: TDateTimePart; + PreviousEffectiveHideDateTimeParts: set of TDateTimePart; +begin + PreviousEffectiveHideDateTimeParts := FEffectiveHideDateTimeParts; + FEffectiveHideDateTimeParts := []; + + for I := Low(TDateTimeParts) to High(TDateTimeParts) do + if I in FHideDateTimeParts then + Include(FEffectiveHideDateTimeParts, I); + + if FKind = dtkDate then + FEffectiveHideDateTimeParts := FEffectiveHideDateTimeParts + + [dtpHour, dtpMinute, dtpSecond, dtpMiliSec, dtpAMPM] + else begin + if FKind = dtkTime then + FEffectiveHideDateTimeParts := FEffectiveHideDateTimeParts + + [dtpDay, dtpMonth, dtpYear]; + + case FTimeDisplay of + tdHM: + FEffectiveHideDateTimeParts := FEffectiveHideDateTimeParts + + [dtpSecond, dtpMiliSec]; + tdHMS: + FEffectiveHideDateTimeParts := FEffectiveHideDateTimeParts + + [dtpMiliSec]; + end; + + if (FTimeFormat = tf24) or (dtpHour in FEffectiveHideDateTimeParts) then + Include(FEffectiveHideDateTimeParts, dtpAMPM); + end; + + if FEffectiveHideDateTimeParts + <> PreviousEffectiveHideDateTimeParts then begin + if GetDateTimePartFromTextPart(FSelectedTextPart) in + FEffectiveHideDateTimeParts then + MoveSelectionLR(False); + + FRecalculatingTextSizesNeeded := True; + UpdateShowArrowButton; + UpdateDate; + end; +end; + +procedure TCustomZVDateTimePicker.SelectDateTimePart( + const DateTimePart: TDateTimePart); +begin + if not (DateTimePart in FEffectiveHideDateTimeParts) then begin + case DateTimePart of + dtpDay: + FSelectedTextPart := FDayPos; + dtpMonth: + FSelectedTextPart := FMonthPos; + dtpYear: + FSelectedTextPart := FYearPos; + else + FSelectedTextPart := 1 + Ord(DateTimePart); + end; + + Invalidate; + end; +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; + +{ GetDateTimePartFromTextPart function + ----------------------------------------------- + Returns part of date/time from the position (1-8). } +function TCustomZVDateTimePicker.GetDateTimePartFromTextPart( + TextPart: TTextPart): TDateTimePart; +begin + Result := TDateTimePart(TextPart - 1); + + 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; + +{ GetSelectedDateTimePart function + --------------------------------- + Returns part of date/time which is currently selected. } +function TCustomZVDateTimePicker.GetSelectedDateTimePart: TDateTimePart; +begin + Result := GetDateTimePartFromTextPart(FSelectedTextPart); +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(IgnoreRightToLeft: Boolean + ): TPoint; +begin + Result.y := BorderSpacing.InnerBorder + BorderWidth; + if Assigned(FCheckBox) then + Result.x := Result.y + FCheckBox.BorderSpacing.Left + + FCheckBox.BorderSpacing.Right + FCheckBox.Width + else + Result.x := Result.y; + + if (not IgnoreRightToLeft) and IsRightToLeft then + Result.x := ClientWidth - Result.x - FTextWidth; +end; + +{ MoveSelectionLR + ----------------- + Moves selection to left or to right. If parameter ToLeft is true, then the + selection moves to left, otherwise to right. } +procedure TCustomZVDateTimePicker.MoveSelectionLR(const ToLeft: Boolean); +var + I, SafetyTextPart: TTextPart; +begin + UpdateIfUserChangedText; + + SafetyTextPart := Low(TTextPart); + I := FSelectedTextPart; + repeat + if ToLeft then begin + if I <= Low(TTextPart) then + I := High(TTextPart) + else + Dec(I); + end else begin + if I >= High(TTextPart) then + I := Low(TTextPart) + else + Inc(I); + end; + + if not (GetDateTimePartFromTextPart(I) + in FEffectiveHideDateTimeParts) then + FSelectedTextPart := I; + + { Is it possible that all parts are hidden? Yes it is! + So we need to ensure that this doesn't loop forever. + When this insurance text part gets to high value, break } + Inc(SafetyTextPart); + until (I = FSelectedTextPart) or (SafetyTextPart >= High(TTextPart)); +end; + +procedure TCustomZVDateTimePicker.KeyDown(var Key: Word; Shift: TShiftState); +var + 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; + MoveSelectionLR(K = VK_LEFT); + 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: TDateTimePart; + N, L: Integer; + YMD: TYMD; + HMSMs: THMSMs; + D, T: TDateTime; + Finished, ForceChange: Boolean; + +begin + if FTextEnabled then begin + Inc(FUserChanging); + try + inherited KeyPress(Key); + + if (not FReadOnly) then begin + Finished := False; + ForceChange := False; + + if FSelectedTextPart = 8 then begin + case upCase(Key) of + 'A': S := 'AM'; + 'P': S := 'PM'; + else + Finished := True; + end; + ForceChange := True; + + end else if Key in ['0'..'9'] then begin + + DTP := GetSelectedDateTimePart; + + if DTP = dtpYear then + N := 4 + else if DTP = dtpMiliSec then + N := 3 + else + N := 2; + + S := Trim(GetSelectedText); + if FUserChangedText and (Length(S) < N) then + S := S + Key + else + S := Key; + + if (Length(S) >= N) then begin + + L := StrToInt(S); + if DTP < dtpHour then begin + YMD := GetYYYYMMDD(True); + case DTP of + dtpDay: YMD.Day := L; + dtpMonth: YMD.Month := L; + dtpYear: YMD.Year := L; + end; + + if TryEncodeDate(YMD.Year, YMD.Month, YMD.Day, D) + and (D >= MinDate) and (D <= MaxDate) then + ForceChange := True + else if N = 4 then begin + UpdateDate; + Finished := True; + end else + S := Key; + + end else begin + if (DTP = dtpHour) and (FTimeFormat = tf12) then begin + if not (L in [1..12]) then + S := Key + else + ForceChange := True; + + end else begin + + HMSMs := GetHMSMs(True); + case DTP of + dtpHour: HMSMs.Hour := L; + dtpMinute: HMSMs.Minute := L; + dtpSecond: HMSMs.Second := L; + dtpMiliSec: HMSMs.MiliSec := L; + end; + if not TryEncodeTime(HMSMs.Hour, HMSMs.Minute, HMSMs.Second, + HMSMs.MiliSec, T) then + S := Key + else + ForceChange := True; + + 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 (not FLeadingZeros) and (FSelectedTextPart <= 4) then + while (Length(S) > 1) and (S[1] = '0') do + Delete(S, 1, 1); + + if FSelectedTextPart <= 3 then + FTextPart[FSelectedTextPart] := S + else + FTimeText[TDateTimePart(FSelectedTextPart - 1)] := S; + + FUserChangedText := True; + + if ForceChange then begin + if FAutoAdvance then begin + MoveSelectionLR(False); + Invalidate; + end else + UpdateIfUserChangedText; + end else + 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 + I, M, NX: Integer; + InTime: Boolean; + DTP: TDateTimePart; +begin + UpdateIfUserChangedText; + SetFocusIfPossible; + + if Focused then begin +// Calculating mouse position inside text +// in order to select date part under mouse cursor. + NX := XMouse - GetTextOrigin.x; + + InTime := False; + if FTimeWidth > 0 then begin + if FDateWidth > 0 then begin + if NX >= FDateWidth + FDigitWidth then begin + InTime := True; + NX := NX - FDateWidth - 2 * FDigitWidth; + end; + end else + InTime := True; + end; + + if InTime then begin + FSelectedTextPart := 8; + + if (dtpAMPM in FEffectiveHideDateTimeParts) or + (NX < FTimeWidth - FAMPMWidth - FDigitWidth div 2) then begin + FSelectedTextPart := 7; + I := 4; + M := FTimeSeparatorWidth div 2; + while I <= 6 do begin + DTP := GetDateTimePartFromTextPart(I); + if not (DTP in FEffectiveHideDateTimeParts) then begin + Inc(M, 2 * FDigitWidth); + if M > NX then begin + FSelectedTextPart := I; + Break; + end; + + Inc(M, FTimeSeparatorWidth); + end; + Inc(I); + end; + end; + + end else if FDateWidth > 0 then begin + + FSelectedTextPart := 3; + I := 1; + M := FSeparatorWidth div 2; + while I <= 2 do begin + if not(GetDateTimePartFromTextPart(I) + in FEffectiveHideDateTimeParts) then begin + if I = FYearPos then + Inc(M, 4 * FDigitWidth) + else if (I = FMonthPos) and FShowMonthNames then + Inc(M, FMonthWidth) + else + Inc(M, 2 * FDigitWidth); + + if M > NX then begin + FSelectedTextPart := I; + Break; + end; + + Inc(M, FSeparatorWidth); + end; + + Inc(I); + end; + + end; + + if GetDateTimePartFromTextPart(FSelectedTextPart) + in FEffectiveHideDateTimeParts then + MoveSelectionLR(True); + + 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(True); + + // We must use TextOrigin's x + y (x is, of course, left margin, but not right + // margin if check box is shown. However, y, which is top margin, 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.SetBiDiMode(AValue: TBiDiMode); +begin + inherited SetBiDiMode(AValue); + ArrangeCtrls; +end; + +procedure TCustomZVDateTimePicker.IncreaseCurrentTextPart; +begin + if DateIsNull then begin + if FSelectedTextPart <= 3 then + SetDateTime(SysUtils.Date) + else + SetDateTime(SysUtils.Now); + + end else begin + case GetSelectedDateTimePart of + dtpDay: IncreaseDay; + dtpMonth: IncreaseMonth; + dtpYear: IncreaseYear; + dtpHour: IncreaseHour; + dtpMinute: IncreaseMinute; + dtpSecond: IncreaseSecond; + dtpMiliSec: IncreaseMiliSec; + dtpAMPM: ChangeAMPM; + 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 GetSelectedDateTimePart of + dtpDay: DecreaseDay; + dtpMonth: DecreaseMonth; + dtpYear: DecreaseYear; + dtpHour: DecreaseHour; + dtpMinute: DecreaseMinute; + dtpSecond: DecreaseSecond; + dtpMiliSec: DecreaseMiliSec; + dtpAMPM: ChangeAMPM; + end; + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseMonth; +var + YMD: TYMD; + N: Word; +begin + SelectMonth; + if Cascade then + SetDateTime(IncMonth(DateTime)) + else begin + 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; +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; + if Cascade then + SetDateTime(IncDay(DateTime)) + else begin + YMD := GetYYYYMMDD(True); + + if YMD.Day >= NumberOfDaysInMonth(YMD.Month, YMD.Year) then + YMD.Day := 1 + else + Inc(YMD.Day); + + SetYYYYMMDD(YMD); + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseMonth; +var + YMD: TYMD; + N: Word; +begin + SelectMonth; + if Cascade then + SetDateTime(IncMonth(DateTime, -1)) + else begin + 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; +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; + if Cascade then + SetDateTime(IncDay(DateTime, -1)) + else begin + YMD := GetYYYYMMDD(True); + + if YMD.Day <= 1 then + YMD.Day := NumberOfDaysInMonth(YMD.Month, YMD.Year) + else + Dec(YMD.Day); + + SetYYYYMMDD(YMD); + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseHour; +var + HMSMs: THMSMs; +begin + SelectHour; + if Cascade then + SetDateTime(IncHour(DateTime)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Hour >= 23 then + HMSMs.Hour := 0 + else + Inc(HMSMs.Hour); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseMinute; +var + HMSMs: THMSMs; +begin + SelectMinute; + if Cascade then + SetDateTime(IncMinute(DateTime)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Minute >= 59 then + HMSMs.Minute := 0 + else + Inc(HMSMs.Minute); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseSecond; +var + HMSMs: THMSMs; +begin + SelectSecond; + if Cascade then + SetDateTime(IncSecond(DateTime)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Second >= 59 then + HMSMs.Second := 0 + else + Inc(HMSMs.Second); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.IncreaseMiliSec; +var + HMSMs: THMSMs; +begin + SelectMiliSec; + if Cascade then + SetDateTime(IncMilliSecond(DateTime)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.MiliSec >= 999 then + HMSMs.MiliSec := 0 + else + Inc(HMSMs.MiliSec); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseHour; +var + HMSMs: THMSMs; +begin + SelectHour; + if Cascade then + SetDateTime(IncHour(DateTime, -1)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Hour <= 0 then + HMSMS.Hour := 23 + else + Dec(HMSMs.Hour); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseMinute; +var + HMSMs: THMSMs; +begin + SelectMinute; + if Cascade then + SetDateTime(IncMinute(DateTime, -1)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Minute <= 0 then + HMSMs.Minute := 59 + else + Dec(HMSMs.Minute); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseSecond; +var + HMSMs: THMSMs; +begin + SelectSecond; + if Cascade then + SetDateTime(IncSecond(DateTime, -1)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.Second <= 0 then + HMSMs.Second := 59 + else + Dec(HMSMs.Second); + + SetHMSMs(HMSMs); + end; +end; + +procedure TCustomZVDateTimePicker.DecreaseMiliSec; +var + HMSMs: THMSMs; +begin + SelectMiliSec; + if Cascade then + SetDateTime(IncMilliSecond(DateTime, -1)) + else begin + HMSMs := GetHMSMs(True); + + if HMSMs.MiliSec <= 0 then + HMSMs.MiliSec := 999 + else + Dec(HMSMs.MiliSec); + + SetHMSMs(HMSMs); + end; +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[dtpHour..dtpAMPM] of Word; + DTP: TDateTimePart; +begin + if HandleAllocated then 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 not FChangeInRecursiveCall then begin // we'll skip the next part in + // recursive calls which could be made through Change or UndoChanges + FChangeInRecursiveCall := True; + try + if FUserChanging > 0 then begin // this means that the change is caused by user interaction + try + Change; + except + UndoChanges; + raise; + end + end else + FConfirmedDateTime := FDateTime; + finally + FChangeInRecursiveCall := False; + end; + end; + + if DateIsNull then begin + if dtpYear in FEffectiveHideDateTimeParts then + FTextPart[FYearPos] := '' + else + FTextPart[FYearPos] := '0000'; + + if dtpMonth in FEffectiveHideDateTimeParts then + FTextPart[FMonthPos] := '' + else + FTextPart[FMonthPos] := '00'; + + if dtpDay in FEffectiveHideDateTimeParts then + FTextPart[FDayPos] := '' + else + FTextPart[FDayPos] := '00'; + + for DTP := dtpHour to dtpAMPM do begin + if DTP in FEffectiveHideDateTimeParts then + FTimeText[DTP] := '' + else if DTP = dtpAMPM then + FTimeText[DTP] := 'XX' + else if DTP = dtpMiliSec then + FTimeText[DTP] := '999' + else + FTimeText[DTP] := '99'; + end; + + end else begin + DecodeDate(FDateTime, W[3], W[2], W[1]); + + if dtpYear in FEffectiveHideDateTimeParts then + FTextPart[FYearPos] := '' + else if FLeadingZeros then + FTextPart[FYearPos] := RightStr('000' + IntToStr(W[3]), 4) + else + FTextPart[FYearPos] := IntToStr(W[3]); + + if dtpMonth in FEffectiveHideDateTimeParts then + FTextPart[FMonthPos] := '' + else if FShowMonthNames then + FTextPart[FMonthPos] := FMonthNamesArray[W[2]] + else if FLeadingZeros then + FTextPart[FMonthPos] := RightStr('0' + IntToStr(W[2]), 2) + else + FTextPart[FMonthPos] := IntToStr(W[2]); + + if dtpDay in FEffectiveHideDateTimeParts then + FTextPart[FDayPos] := '' + else if FLeadingZeros then + FTextPart[FDayPos] := RightStr('0' + IntToStr(W[1]), 2) + else + FTextPart[FDayPos] := IntToStr(W[1]); + + DecodeTime(FDateTime, WT[dtpHour], WT[dtpMinute], WT[dtpSecond], WT[dtpMiliSec]); + + if dtpAMPM in FEffectiveHideDateTimeParts then + FTimeText[dtpAMPM] := '' + else begin + if WT[dtpHour] < 12 then begin + FTimeText[dtpAMPM] := 'AM'; + if WT[dtpHour] = 0 then + WT[dtpHour] := 12; + end else begin + FTimeText[dtpAMPM] := 'PM'; + if WT[dtpHour] > 12 then + Dec(WT[dtpHour], 12); + end; + end; + + for DTP := dtpHour to dtpMiliSec do begin + if DTP in FEffectiveHideDateTimeParts then + FTimeText[DTP] := '' + else if (DTP = dtpHour) and (not FLeadingZeros) then + FTimeText[DTP] := IntToStr(WT[dtpHour]) + else if DTP = dtpMiliSec then + FTimeText[DTP] := RightStr('00' + IntToStr(WT[DTP]), 3) + else + FTimeText[DTP] := RightStr('0' + IntToStr(WT[DTP]), 2); + + end; + + end; + + Invalidate; + end; +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 + SelectDateTimePart(dtpDay); +end; + +procedure TCustomZVDateTimePicker.SelectMonth; +begin + SelectDateTimePart(dtpMonth); +end; + +procedure TCustomZVDateTimePicker.SelectYear; +begin + SelectDateTimePart(dtpYear); +end; + +procedure TCustomZVDateTimePicker.SelectHour; +begin + SelectDateTimePart(dtpHour); +end; + +procedure TCustomZVDateTimePicker.SelectMinute; +begin + SelectDateTimePart(dtpMinute); +end; + +procedure TCustomZVDateTimePicker.SelectSecond; +begin + SelectDateTimePart(dtpSecond); +end; + +procedure TCustomZVDateTimePicker.SelectMiliSec; +begin + SelectDateTimePart(dtpMiliSec); +end; + +procedure TCustomZVDateTimePicker.SelectAMPM; +begin + SelectDateTimePart(dtpAMPM); +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. } + UpdateDate; + 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; +var + C: TControl; +begin + if not FDoNotArrangeControls then begin //Read the note above CreateWnd procedure. + DisableAlign; + try + if GetShowCheckBox then begin + if IsRightToLeft then begin + FCheckBox.Align := alRight; + FCheckBox.BorderSpacing.Left := 0; + FCheckBox.BorderSpacing.Right := 2; + end else begin + FCheckBox.Align := alLeft; + FCheckBox.BorderSpacing.Left := 2; + FCheckBox.BorderSpacing.Right := 0; + end; + FCheckBox.BringToFront; + end; + + if Assigned(FUpDown) then + C := FUpDown + else if Assigned(FArrowButton) then + C := FArrowButton + else + C := nil; + + if Assigned(C) then begin + if IsRightToLeft then + C.Align := alLeft + else + C.Align := alRight; + + C.BringToFront; + 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) + or (GetDateTimePartFromTextPart(FSelectedTextPart) + in FEffectiveHideDateTimeParts) then + FSelectedTextPart := 1; + + if GetDateTimePartFromTextPart(FSelectedTextPart) + in FEffectiveHideDateTimeParts then + MoveSelectionLR(False); + + Invalidate; +end; + +procedure TCustomZVDateTimePicker.SelectTime; +begin + if (FSelectedTextPart < 4) + or (GetDateTimePartFromTextPart(FSelectedTextPart) + in FEffectiveHideDateTimeParts) then + FSelectedTextPart := 4; + + if GetDateTimePartFromTextPart(FSelectedTextPart) + in FEffectiveHideDateTimeParts then + MoveSelectionLR(False); + + Invalidate; +end; + +procedure TCustomZVDateTimePicker.Paint; +var + I, M, N, K, L: Integer; + DD: Array[1..8] of Integer; + R: TRect; + SelectStep: 0..8; + TextStyle: TTextStyle; + DTP: TDateTimePart; + S: String; + +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; + TextStyle.RightToLeft := IsRightToLeft; + + if DateIsNull and (FTextForNullDate > '') + and (not (FTextEnabled and Focused)) then begin + + if IsRightToLeft then begin + TextStyle.Alignment := taRightJustify; + R.Right := R.Left + FTextWidth; + R.Left := 0; + end else begin + TextStyle.Alignment := taLeftJustify; + R.Right := Width; + end; + + 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 dtpYear in FEffectiveHideDateTimeParts then begin + DD[FYearPos] := 0; + M := 4; + L := 0; + end else begin + DD[FYearPos] := 4 * FDigitWidth; + M := FYearPos; + L := FYearPos; + end; + + if dtpMonth in FEffectiveHideDateTimeParts then + DD[FMonthPos] := 0 + else begin + if FShowMonthNames then + DD[FMonthPos] := FMonthWidth + else + DD[FMonthPos] := 2 * FDigitWidth; + + if FMonthPos < M then + M := FMonthPos; + + if FMonthPos > L then + L := FMonthPos; + + end; + + if dtpDay in FEffectiveHideDateTimeParts then + DD[FDayPos] := 0 + else begin + DD[FDayPos] := 2 * FDigitWidth; + if FDayPos < M then + M := FDayPos; + if FDayPos > L then + L := FDayPos; + end; + + N := 3; + K := 3; + for DTP := dtpHour to dtpAMPM do begin + I := Ord(DTP) + 1; + if DTP in FEffectiveHideDateTimeParts then + DD[I] := 0 + else if DTP = dtpAMPM then begin + DD[I] := FAMPMWidth; + N := I; + end else begin + if DTP = dtpMiliSec then + DD[I] := 3 * FDigitWidth + else + DD[I] := 2 * FDigitWidth; + + if K < I then + K := I; + end; + + if N < K then + N := K; + + end; + + for I := M to N do begin + if DD[I] <> 0 then begin + + R.Right := R.Left + DD[I]; + if I <= 3 then begin + if (I = FMonthPos) and FShowMonthNames then begin + TextStyle.Alignment := taCenter; + if DateIsNull then + S := FNullMonthText + else + S := FTextPart[I]; + end else + S := FTextPart[I]; + + end else + S := FTimeText[TDateTimePart(I - 1)]; + + if I = SelectStep then begin + TextStyle.Opaque := True; + Canvas.Brush.Color := clHighlight; + Canvas.Font.Color := clHighlightText; + + Canvas.TextRect(R, R.Left, R.Top, S, TextStyle); + + TextStyle.Opaque := False; + Canvas.Brush.Color := Color; + Canvas.Font.Color := Self.Font.Color; + end else + Canvas.TextRect(R, R.Left, R.Top, S, TextStyle); + + TextStyle.Alignment := taRightJustify; + R.Left := R.Right; + + if I < L then begin + R.Right := R.Left + FSeparatorWidth; + if not ((I = FMonthPos) and FShowMonthNames) then + Canvas.TextRect(R, R.Left, R.Top, FDateSeparator, TextStyle); + end else if I > L 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 FTimeWidth > 0 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 + Inc(FUserChanging); + try + if Button = btNext then + IncreaseCurrentTextPart + else + DecreaseCurrentTextPart; + finally + Dec(FUserChanging); + end; + 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; + +const + DefaultUpDownWidth = 15; + DefaultArrowButtonWidth = DefaultUpDownWidth + 2; + +procedure TCustomZVDateTimePicker.SetAutoButtonSize(AValue: Boolean); +begin + if FAutoButtonSize <> AValue then begin + FAutoButtonSize := AValue; + + if AValue then + AutoResizeButton + else begin + if Assigned(FUpDown) then + FUpDown.Width := DefaultUpDownWidth + else if Assigned(FArrowButton) then + FArrowButton.Width := DefaultArrowButtonWidth; + end; + + end; +end; + +procedure TCustomZVDateTimePicker.SetCalendarWrapperClass( + AValue: TCalendarControlWrapperClass); +begin + if FCalendarWrapperClass = AValue then Exit; + FCalendarWrapperClass := AValue; +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.AutoResizeButton; +begin + if Assigned(FArrowButton) then + FArrowButton.Width := MulDiv(ClientHeight, 9, 10) + else if Assigned(FUpDown) then + FUpDown.Width := MulDiv(ClientHeight, 79, 100); + +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; + +procedure TCustomZVDateTimePicker.WMSize(var Message: TLMSize); +begin + inherited WMSize(Message); + + if FAutoButtonSize then + AutoResizeButton; +end; + +procedure TCustomZVDateTimePicker.DropDownCalendarForm; +begin + SetFocusIfPossible; + + if FAllowDroppingCalendar then begin + if not (FReadOnly or Assigned(FCalendarForm) + or (csDesigning in ComponentState)) then begin + FCalendarForm := TDTCalendarForm.CreateNewDTCalendarForm(nil, Self); + 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; + + 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, DefaultArrowButtonWidth, 1); + + 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, DefaultUpDownWidth, 1); + + FUpDown.Parent := Self; + + TDTUpDown(FUPDown).OnClick := @UpDownClick; + + end; + end; + +var + ReallyShowArrowButton: Boolean; + +begin + if FDateMode = dmNone then begin + DestroyArrowBtn; + DestroyUpDown; + + end else begin + ReallyShowArrowButton := (FDateMode = dmComboBox) and + not (dtpDay in FEffectiveHideDateTimeParts); + + if (ReallyShowArrowButton <> Assigned(FArrowButton)) or + (Assigned(FArrowButton) = Assigned(FUpDown)) then begin + DisableAlign; + try + if ReallyShowArrowButton then + CreateArrowBtn + else + CreateUpDown; + + ArrangeCtrls; + + finally + EnableAlign; + end; + 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; + DTP: TDateTimePart; +begin + inherited Create(AOwner); + + with GetControlClassDefaultSize do + SetInitialBounds(0, 0, cx, cy); + + FChangeInRecursiveCall := False; + 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; + FMonthWidth := 0; + FHideDateTimeParts := []; + FShowMonthNames := False; + FNullMonthText := ''; + + for I := Low(FTextPart) to High(FTextPart) do + FTextPart[I] := ''; + + for DTP := dtpHour to dtpAMPM do + FTimeText[DTP] := ''; + + 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; + FCascade := False; + FAutoButtonSize := False; + FAutoAdvance := True; + FCalendarWrapperClass := nil; + FEffectiveHideDateTimeParts := []; + + AdjustEffectiveDateDisplayOrder; + AdjustEffectiveHideDateTimeParts; + + SetMonthNames('Long'); + SetDateMode(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.5/zvdatetimepickerpropedit.pas b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimepickerpropedit.pas new file mode 100644 index 000000000..37b05d106 --- /dev/null +++ b/components/ZVDateTimeCtrls/tags/1.5/zvdatetimepickerpropedit.pas @@ -0,0 +1,513 @@ +{ +ZVDateTimePickerPropEdit +- - - - - - - - - - - - - - - - - +Author: Zoran Vučenović, January and February 2010 + Зоран Вученовић, јануар и фебруар 2010. + + 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; + M: TMonitor; + AnchKindTrailing, AnchKindLeading: TAnchorKind; +begin + if Assigned(Caller) then begin + CallerZVDateTimePicker := Caller; + Prop := UpperCase(PropertyName); + BiDiMode := CallerZVDateTimePicker.BiDiMode; + + 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; + DTP[I].AutoAdvance := CallerZVDateTimePicker.AutoAdvance; + DTP[I].CalendarWrapperClass := CallerZVDateTimePicker.CalendarWrapperClass; + end; + ZVDateTimePicker1.TextForNullDate := CallerZVDateTimePicker.TextForNullDate; + ZVDateTimePicker1.TimeSeparator := CallerZVDateTimePicker.TimeSeparator; + ZVDateTimePicker1.TimeDisplay := tdHMSMs; + ZVDateTimePicker1.TimeFormat := CallerZVDateTimePicker.TimeFormat; + + if IsRightToLeft then begin + AnchKindLeading := akRight; + AnchKindTrailing := akLeft; + end else begin + AnchKindLeading := akLeft; + AnchKindTrailing := akRight; + end; + + ZVDateTimePickerMax.AnchorParallel(akTop, 20, Self); + ZVDateTimePickerMax.AnchorParallel(AnchKindTrailing, 20, Self); + LabelMax.AnchorVerticalCenterTo(ZVDateTimePickerMax); + LabelMax.AnchorToNeighbour(AnchKindTrailing, 2, ZVDateTimePickerMax); + ZVDateTimePickerMin.AnchorParallel(akTop, 20, Self); + ZVDateTimePickerMin.AnchorToNeighbour(AnchKindTrailing, 20, LabelMax); + LabelMin.AnchorToNeighbour(AnchKindTrailing, 2, ZVDateTimePickerMin); + LabelMin.AnchorVerticalCenterTo(ZVDateTimePickerMin); + ZVDateTimePicker1.AnchorParallel(AnchKindLeading, 0, ZVDateTimePickerMin); + ZVDateTimePicker1.AnchorToNeighbour(akTop, 20, ZVDateTimePickerMin); + Label1.AnchorToNeighbour(AnchKindTrailing, 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; + + M := Screen.MonitorFromWindow(CallerZVDateTimePicker.Handle); + + R := M.WorkareaRect; + // But if WorkareaRect doesn't work (not implemented for all widgetsets), + // then take BoundsRect: + if (R.Right <= R.Left) or (R.Bottom <= R.Top) then + R := M.BoundsRect; + + 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.