Browse Source

- New repository.
- LoadFromFile / SaveToFile for bcbutton.pas

lainz 10 years ago
commit
4f2ce5b5d5
100 changed files with 28004 additions and 0 deletions
  1. 481 0
      COPYING.LGPL.txt
  2. 24 0
      COPYING.modifiedLGPL.txt
  3. 2 0
      DataType.inc
  4. 406 0
      bcbasectrls.pas
  5. 1624 0
      bcbutton.pas
  6. 31 0
      bcbutton_icon.lrs
  7. 210 0
      bceffect.pas
  8. 776 0
      bcfilters.pas
  9. 239 0
      bcgamegrid.pas
  10. 63 0
      bcgamegrid_icon.lrs
  11. 1008 0
      bcimagebutton.pas
  12. 45 0
      bcimagebutton_icon.lrs
  13. 327 0
      bclabel.pas
  14. 26 0
      bclabel_icon.lrs
  15. 451 0
      bcpanel.pas
  16. 9 0
      bcpanel_icon.lrs
  17. 327 0
      bcrtti.pas
  18. 234 0
      bcstylesform.lfm
  19. 484 0
      bcstylesform.pas
  20. 472 0
      bctools.pas
  21. 821 0
      bctypes.pas
  22. 156 0
      bgracontrols.lpk
  23. 38 0
      bgracontrols.pas
  24. 222 0
      bgraflashprogressbar.pas
  25. 46 0
      bgraflashprogressbar_icon.lrs
  26. 252 0
      bgragraphiccontrol.pas
  27. 51 0
      bgragraphiccontrol_icon.lrs
  28. 135 0
      bgraimagelist.pas
  29. 40 0
      bgraimagelist_icon.lrs
  30. 2646 0
      bgraimagemanipulation.pas
  31. 13 0
      bgraimagemanipulation_icon.lrs
  32. 482 0
      bgraknob.pas
  33. 66 0
      bgraknob_icon.lrs
  34. 394 0
      bgrashape.pas
  35. 47 0
      bgrashape_icon.lrs
  36. 126 0
      bgraspeedbutton.pas
  37. 28 0
      bgraspeedbutton_icon.lrs
  38. 594 0
      bgraspriteanimation.pas
  39. 13 0
      bgraspriteanimation_icon.lrs
  40. 295 0
      bgravirtualscreen.pas
  41. 47 0
      bgravirtualscreen_icon.lrs
  42. 48 0
      readme.txt
  43. 193 0
      styles/facebook-dark.bcbtn
  44. 193 0
      styles/facebook.bcbtn
  45. 107 0
      styles/facebook.bcpnl
  46. 107 0
      styles/flashsetup-grey.bcpnl
  47. 107 0
      styles/flashsetup-red.bcpnl
  48. 203 0
      styles/flashsetup.bcbtn
  49. 193 0
      styles/google-menu.bcbtn
  50. 193 0
      styles/google-search.bcbtn
  51. 107 0
      styles/google.bcpnl
  52. 193 0
      styles/lainz.bcbtn
  53. 203 0
      styles/macosx-lion.bcbtn
  54. 173 0
      styles/mora.bcbtn
  55. 203 0
      styles/office2010.bcbtn
  56. 108 0
      styles/windows7-toolbar.bcpnl
  57. 203 0
      styles/windows7-toolbutton.bcbtn
  58. 203 0
      styles/windows7.bcbtn
  59. 134 0
      test/test_bccontrols/test_bcbutton/bcsample.lpi
  60. 21 0
      test/test_bccontrols/test_bcbutton/bcsample.lpr
  61. 3741 0
      test/test_bccontrols/test_bcbutton/unit1.lfm
  62. 80 0
      test/test_bccontrols/test_bcbutton/unit1.pas
  63. 843 0
      test/test_bccontrols/test_bccontrols/bcsamples.pas
  64. 142 0
      test/test_bccontrols/test_bccontrols/bctest.lpi
  65. 22 0
      test/test_bccontrols/test_bccontrols/bctest.lpr
  66. 1714 0
      test/test_bccontrols/test_bccontrols/ubctest.lfm
  67. 180 0
      test/test_bccontrols/test_bccontrols/ubctest.pas
  68. BIN
      test/test_bccontrols/test_bcfilters/Penguins.jpg
  69. 93 0
      test/test_bccontrols/test_bcfilters/test_bcfilters.lpi
  70. 21 0
      test/test_bccontrols/test_bcfilters/test_bcfilters.lpr
  71. 96 0
      test/test_bccontrols/test_bcfilters/unit1.lfm
  72. 122 0
      test/test_bccontrols/test_bcfilters/unit1.pas
  73. 134 0
      test/test_bccontrols/test_bcgamegrid/test_bcgamegrid.lpi
  74. 21 0
      test/test_bccontrols/test_bcgamegrid/test_bcgamegrid.lpr
  75. 39 0
      test/test_bccontrols/test_bcgamegrid/umain.lfm
  76. 9 0
      test/test_bccontrols/test_bcgamegrid/umain.lrs
  77. 213 0
      test/test_bccontrols/test_bcgamegrid/umain.pas
  78. BIN
      test/test_bccontrols/test_bcimagebutton/sample_1.png
  79. BIN
      test/test_bccontrols/test_bcimagebutton/sample_2.png
  80. BIN
      test/test_bccontrols/test_bcimagebutton/sample_3.png
  81. BIN
      test/test_bccontrols/test_bcimagebutton/sample_4.png
  82. BIN
      test/test_bccontrols/test_bcimagebutton/sample_5.png
  83. 134 0
      test/test_bccontrols/test_bcimagebutton/test.lpi
  84. 21 0
      test/test_bccontrols/test_bcimagebutton/test.lpr
  85. 90 0
      test/test_bccontrols/test_bcimagebutton/unit1.lfm
  86. 48 0
      test/test_bccontrols/test_bcimagebutton/unit1.pas
  87. BIN
      test/test_bccontrols/test_bcxbutton/Desert.jpg
  88. 134 0
      test/test_bccontrols/test_bcxbutton/test_bcxbutton.lpi
  89. 21 0
      test/test_bccontrols/test_bcxbutton/test_bcxbutton.lpr
  90. 75 0
      test/test_bccontrols/test_bcxbutton/utest.lfm
  91. 254 0
      test/test_bccontrols/test_bcxbutton/utest.pas
  92. BIN
      test/test_bgracontrols/test_bgraimagemanipulation/ProjectBGRAImageManipulationDemo.ico
  93. 465 0
      test/test_bgracontrols/test_bgraimagemanipulation/ProjectBGRAImageManipulationDemo.lpi
  94. 19 0
      test/test_bgracontrols/test_bgraimagemanipulation/ProjectBGRAImageManipulationDemo.lpr
  95. 2045 0
      test/test_bgracontrols/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.lfm
  96. 218 0
      test/test_bgracontrols/test_bgraimagemanipulation/unitbgraimagemanipulationdemo.pas
  97. 93 0
      test/test_extra/effect_fading/fading.lpi
  98. 21 0
      test/test_extra/effect_fading/fading.lpr
  99. 104 0
      test/test_extra/effect_fading/unit1.lfm
  100. 149 0
      test/test_extra/effect_fading/unit1.pas

+ 481 - 0
COPYING.LGPL.txt

@@ -0,0 +1,481 @@
+		  GNU LIBRARY GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+    		    59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!

+ 24 - 0
COPYING.modifiedLGPL.txt

@@ -0,0 +1,24 @@
+This is the file COPYING.modifiedLGPL, it applies to all units of the
+"BGRA Controls" library.
+
+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.
+
+
+If you didn't receive a copy of the file COPYING.LGPL, contact:
+      Free Software Foundation, Inc.,
+      675 Mass Ave
+      Cambridge, MA  02139
+      USA
+

+ 2 - 0
DataType.inc

@@ -0,0 +1,2 @@
+type
+  TCoord = packed record
    x1 : LongInt;
    y1 : LongInt;
    x2 : LongInt;
    y2 : LongInt;
  end;

  TRatio = packed record
    Horizontal : LongInt;
    Vertical : LongInt;
  end;

  TCardinalDirection = (NORTH, SOUTH, WEST, EAST);
  TDirection = set of TCardinalDirection;

  TSizeLimits = packed record
    minWidth  : LongInt;
    maxWidth  : LongInt;
    minHeight : LongInt;
    maxHeight : LongInt;
  end;


+ 406 - 0
bcbasectrls.pas

@@ -0,0 +1,406 @@
+{ Base framework classes
+
+  Copyright (C) 2012 Krzysztof Dibowski dibowski at interia.pl
+
+  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 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.
+
+  This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+
+unit BCBaseCtrls;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, BGRABitmap, BGRABitmapTypes;
+
+type
+
+  TOnBCPropertyChange = procedure(ASender: TObject; AData: PtrInt) of object;
+
+  { TBCProperty
+    Base BC Property with OnChange event support
+  }
+
+  TBCProperty = class(TPersistent)
+  private
+    FOnChange: TOnBCPropertyChange;
+  protected
+    FControl: TControl;
+    procedure Change(AData: PtrInt = 0); virtual;
+  public
+    constructor Create(AControl: TControl); virtual;
+  public
+    property Control: TControl read FControl;
+    property OnChange: TOnBCPropertyChange read FOnChange write FOnChange;
+  end;
+
+  { TBGRABitmapEx
+    Some BGRABitmap descendant which can store custom data and has NeedRender flag
+  }
+
+  TBGRABitmapEx = class(TBGRABitmap)
+  private
+    FCustomData: PtrInt;
+    FNeedRender: Boolean;
+  protected
+    procedure Init; override;
+  public
+    property NeedRender: Boolean read FNeedRender write FNeedRender;
+    property CustomData: PtrInt read FCustomData write FCustomData;
+  end;
+
+  { TBCGraphicControl
+    BC graphic control with some basic functionality like begin/end update and
+    debug functions
+  }
+
+  TBCGraphicControl = class(TGraphicControl)
+  private
+    {$IFDEF DEBUG}
+    FPaintCount: Integer;
+    {$ENDIF}
+    FUpdateCount: Integer;
+  protected
+    procedure DoOnResize; override;
+  protected
+    {$IFDEF DEBUG}
+    function GetDebugText: String; virtual;
+    {$ENDIF}
+    procedure Paint; override; // do not override in descendants!
+    // All descendants should use DrawControl method instead of Paint.
+    // DrawControl is not called between BeginUpdate and EndUpdate
+    procedure DrawControl; virtual;
+    // This method is called when control should be rendered (when some
+    // general action occur which change "body" e.g. resize)
+    procedure RenderControl; virtual;
+  public
+    constructor Create(AOwner: TComponent); override;
+    // This disable DrawControl method
+    procedure BeginUpdate; virtual;
+    // This enable DrawControl method
+    procedure EndUpdate; virtual;
+    // Called on EndUpdate if FUpdateCount is 0
+    procedure UpdateControl; virtual;
+    // Check if BeginUpdate was called
+    function IsUpdating: Boolean;
+  end;
+
+  { TBCStyleDummyProperty
+    This is only dummy property type for access to style editor from
+    object inspector
+  }
+
+  TBCStyleDummyProperty = class(TBCProperty)
+
+  end;
+
+  { TBCStyleGraphicControl
+    All descendants of this class have support for saving and loading styles and
+    access to style editor from object inspector or component context menu
+  }
+
+  TBCStyleGraphicControl = class(TBCGraphicControl)
+  private
+    FAssignStyle: TBCStyleDummyProperty;
+  protected
+    function GetStyleExtension: String; virtual; abstract;
+    // Dummy property for access to style editor dialog
+    property AssignStyle: TBCStyleDummyProperty read FAssignStyle;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    property StyleExtension: String read GetStyleExtension;
+  end;
+
+  { TBCCustomControl
+    BC custom control with some basic functionality like begin/end update and
+    debug functions
+  }
+
+  TBCCustomControl = class(TCustomControl)
+  private
+    {$IFDEF DEBUG}
+    FPaintCount: Integer;
+    {$ENDIF}
+    FUpdateCount: Integer;
+  protected
+    procedure DoOnResize; override;
+  protected
+    {$IFDEF DEBUG}
+    function GetDebugText: String; virtual;
+    {$ENDIF}
+    procedure Paint; override; // do not override in descendants!
+    // All descendants should use DrawControl method instead of Paint.
+    // DrawControl is not called between BeginUpdate and EndUpdate
+    procedure DrawControl; virtual;
+    // This method is called when control should be rendered (when some
+    // general action occur which change "body" e.g. resize)
+    procedure RenderControl; virtual;
+  public
+    constructor Create(AOwner: TComponent); override;
+    // This disable DrawControl method
+    procedure BeginUpdate; virtual;
+    // This enable DrawControl method
+    procedure EndUpdate; virtual;
+    // Called on EndUpdate if FUpdateCount is 0
+    procedure UpdateControl; virtual;
+    // Check if BeginUpdate was called
+    function IsUpdating: Boolean;
+  end;
+
+  { TBCStyleCustomControl
+    All descendants of this class have support for saving and loading styles and
+    access to style editor from object inspector or component context menu
+  }
+
+  TBCStyleCustomControl = class(TBCCustomControl)
+  private
+    FAssignStyle: TBCStyleDummyProperty;
+  protected
+    function GetStyleExtension: String; virtual; abstract;
+    // Dummy property for access to style editor dialog
+    property AssignStyle: TBCStyleDummyProperty read FAssignStyle;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    property StyleExtension: String read GetStyleExtension;
+  end;
+
+procedure Register;
+
+implementation
+
+{$IFDEF DEBUG} uses Graphics; {$ENDIF}
+
+procedure Register;
+begin
+  RegisterNoIcon([TBCCustomControl]);
+end;
+
+{ TBCStyleCustomControl }
+
+constructor TBCStyleCustomControl.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  FAssignStyle := TBCStyleDummyProperty.Create(Self);
+end;
+
+destructor TBCStyleCustomControl.Destroy;
+begin
+  FAssignStyle.Free;
+  inherited Destroy;
+end;
+
+{ TBCStyleGraphicControl }
+
+constructor TBCStyleGraphicControl.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  FAssignStyle := TBCStyleDummyProperty.Create(Self);
+end;
+
+destructor TBCStyleGraphicControl.Destroy;
+begin
+  FAssignStyle.Free;
+  inherited Destroy;
+end;
+
+{ TBCCustomControl }
+
+procedure TBCCustomControl.DoOnResize;
+begin
+  inherited DoOnResize;
+  RenderControl;
+end;
+
+{$IFDEF DEBUG}
+function TBCCustomControl.GetDebugText: String;
+begin
+  Result := EmptyStr;
+end;
+{$ENDIF}
+
+procedure TBCCustomControl.Paint;
+begin
+  if (csCreating in FControlState) or IsUpdating then
+    Exit;
+
+  DrawControl;
+  {$IFDEF DEBUG}
+  FPaintCount += 1;
+  Canvas.Brush.Style := bsSolid;
+  Canvas.Brush.Color := clBlack;
+  Canvas.Font.Color := clWhite;
+  Canvas.TextOut(1,1,'P: '+IntToStr(FPaintCount)+' '+GetDebugText);
+  {$ENDIF}
+  inherited Paint;
+end;
+
+procedure TBCCustomControl.DrawControl;
+begin
+
+end;
+
+procedure TBCCustomControl.RenderControl;
+begin
+
+end;
+
+constructor TBCCustomControl.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  {$IFDEF DEBUG}
+  FPaintCount := 0;
+  {$ENDIF}
+end;
+
+procedure TBCCustomControl.BeginUpdate;
+begin
+  FUpdateCount += 1;
+end;
+
+procedure TBCCustomControl.EndUpdate;
+begin
+  if FUpdateCount > 0 then
+  begin
+    FUpdateCount -= 1;
+    if FUpdateCount=0 then
+      UpdateControl;
+  end;
+end;
+
+procedure TBCCustomControl.UpdateControl;
+begin
+  Self.Invalidate;
+end;
+
+function TBCCustomControl.IsUpdating: Boolean;
+begin
+  Result := FUpdateCount>0;
+end;
+
+{ TBCProperty }
+
+procedure TBCProperty.Change(AData: PtrInt);
+begin
+  if Assigned(FOnChange) then
+    FOnChange(Self,AData);
+end;
+
+constructor TBCProperty.Create(AControl: TControl);
+begin
+  FControl := AControl;
+
+  inherited Create;
+end;
+
+{ TBCGraphicControl }
+
+procedure TBCGraphicControl.DoOnResize;
+begin
+  inherited DoOnResize;
+  RenderControl;
+end;
+
+{$IFDEF DEBUG}
+function TBCGraphicControl.GetDebugText: String;
+begin
+  Result := EmptyStr;
+end;
+{$ENDIF}
+
+procedure TBCGraphicControl.Paint;
+begin
+  //inherited Paint;
+  if (csCreating in FControlState) or IsUpdating then
+    Exit;
+  DrawControl;
+  {$IFDEF DEBUG}
+  FPaintCount += 1;
+  Canvas.Brush.Style := bsSolid;
+  Canvas.Brush.Color := clBlack;
+  Canvas.Font.Color := clWhite;
+  Canvas.TextOut(1,1,'P: '+IntToStr(FPaintCount)+' '+GetDebugText);
+  {$ENDIF}
+end;
+
+procedure TBCGraphicControl.DrawControl;
+begin
+
+end;
+
+procedure TBCGraphicControl.RenderControl;
+begin
+
+end;
+
+constructor TBCGraphicControl.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  {$IFDEF DEBUG}
+  FPaintCount := 0;
+  {$ENDIF}
+end;
+
+procedure TBCGraphicControl.BeginUpdate;
+begin
+  FUpdateCount += 1;
+end;
+
+procedure TBCGraphicControl.EndUpdate;
+begin
+  if FUpdateCount > 0 then
+  begin
+    FUpdateCount -= 1;
+    if FUpdateCount=0 then
+      UpdateControl;
+  end;
+end;
+
+procedure TBCGraphicControl.UpdateControl;
+begin
+  Invalidate;
+end;
+
+function TBCGraphicControl.IsUpdating: Boolean;
+begin
+  Result := FUpdateCount>0;
+end;
+
+{ TBGRABitmapEx }
+
+procedure TBGRABitmapEx.Init;
+begin
+  inherited Init;
+  FNeedRender := True;
+  FCustomData := 0;
+end;
+
+end.
+

+ 1624 - 0
bcbutton.pas

@@ -0,0 +1,1624 @@
+{ Customizable component which using BGRABitmap for drawing. Control mostly rendered
+  using framework.
+
+  Functionality:
+  - Gradients
+  - Double gradients
+  - Rounding
+  - Drop down list
+  - Glyph
+  - States (normal, hover, clicked)
+  - Caption with shadow
+  - Full alpha and antialias support
+
+  Copyright (C) 2012 Krzysztof Dibowski dibowski at interia.pl
+
+  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 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.
+
+  This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+
+unit BCButton;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, LResources, Controls, Dialogs, BGRABitmap, BGRABitmapTypes,
+  ActnList, ImgList, Menus, // MORA
+  Buttons, Graphics, LCLType, types, BCTypes, Forms, BCBasectrls;
+
+{off $DEFINE DEBUG}
+
+type
+
+  TBCButtonState = class;
+  TBCButtonStyle = (bbtButton, bbtDropDown);
+  TOnAfterRenderBCButton = procedure(Sender: TObject; const ABGRA: TBGRABitmap;
+    AState: TBCButtonState; ARect: TRect) of object;
+  TBCButtonPropertyData = (pdNone, pdUpdateSize);
+
+  // MORA: DropDown styles
+  TBCButtonDropDownStyle = (
+    bdsSeparate,     // DropDown is a separate button (default)
+    bdsCommon        // DropDown is same as main button
+    ); //
+  TBCButtonDropDownPosition = (
+    bdpLeft,         // default
+    bdpBottom);
+
+  { TBCButtonState }
+
+  TBCButtonState = class(TBCProperty)
+  private
+    FBackground: TBCBackground;
+    FBorder: TBCBorder;
+    FFontEx: TBCFont;
+    procedure OnChangeFont(Sender: TObject; AData: PtrInt);
+    procedure OnChangeChildProperty(Sender: TObject; AData: PtrInt);
+    procedure SetBackground(AValue: TBCBackground);
+    procedure SetBorder(AValue: TBCBorder);
+    procedure SetFontEx(const AValue: TBCFont);
+  public
+    constructor Create(AControl: TControl); override;
+    destructor Destroy; override;
+
+    procedure Assign(Source: TPersistent); override;
+  published
+    property Background: TBCBackground read FBackground write SetBackground;
+    property Border: TBCBorder read FBorder write SetBorder;
+    property FontEx: TBCFont read FFontEx write SetFontEx;
+  end;
+
+  { TCustomBCButton }
+
+  TCustomBCButton = class(TBCStyleGraphicControl)
+  private
+    { Private declarations }
+    {$IFDEF DEBUG}
+    FRenderCount: Integer;
+    {$ENDIF}
+    FDropDownArrowSize: Integer;
+    FDropDownWidth: Integer;
+    FFlipArrow: boolean;
+    FActiveButt: TBCButtonStyle;
+    FBGRANormal, FBGRAHover, FBGRAClick: TBGRABitmapEx;
+    FRounding: TBCRounding;
+    FRoundingDropDown: TBCRounding;
+    FStateClicked: TBCButtonState;
+    FStateHover: TBCButtonState;
+    FStateNormal: TBCButtonState;
+    FDown: boolean;
+    FGlyph: TBitmap;
+    FGlyphMargin: integer;
+    FButtonState: TBCMouseState;
+    FDownButtonState: TBCMouseState;
+    FOnAfterRenderBCButton: TOnAfterRenderBCButton;
+    FOnButtonClick: TNotifyEvent;
+    FStaticButton: boolean;
+    FStyle: TBCButtonStyle;
+    FGlobalOpacity: byte;
+    FTextApplyGlobalOpacity: boolean;
+    AutoSizeExtraY: integer;
+    AutoSizeExtraX: integer;
+    // MORA
+    FClickOffest: Boolean;
+    FDropDownArrow: Boolean;
+    FDropDownMenu: TPopupMenu;
+    FDropDownMenuVisible: Boolean;
+    FDropDownPosition: TBCButtonDropDownPosition;
+    FDropDownStyle: TBCButtonDropDownStyle;
+    FImageChangeLink: TChangeLink;
+    FImageIndex: Integer;
+    FImages: TCustomImageList;
+    FSaveDropDownClosed: TNotifyEvent;
+    FShowCaption: Boolean;
+    procedure AssignDefaultStyle;
+    procedure CalculateGlyphSize(var NeededWidth, NeededHeight: integer);
+    procedure ConvertToGrayScale(ABGRA: TBGRABitmap);
+    procedure DropDownClosed(Sender: TObject);
+    procedure RenderAll(ANow: Boolean = False);
+    function GetButtonRect: TRect;
+    function GetDropDownWidth(AFull: boolean = True): integer;
+    function GetDropDownRect(AFull: Boolean = True): TRect;
+    procedure SeTBCButtonStateClicked(const AValue: TBCButtonState);
+    procedure SeTBCButtonStateHover(const AValue: TBCButtonState);
+    procedure SeTBCButtonStateNormal(const AValue: TBCButtonState);
+    procedure SetClickOffset(AValue: Boolean);
+    procedure SetDown(AValue: boolean);
+    procedure SetDropDownArrow(AValue: Boolean);
+    procedure SetDropDownArrowSize(AValue: Integer);
+    procedure SetDropDownPosition(AValue: TBCButtonDropDownPosition);
+    procedure SetDropDownWidth(AValue: Integer);
+    procedure SetFlipArrow(AValue: boolean);
+    procedure SetGlyph(const AValue: TBitmap);
+    procedure SetGlyphMargin(const AValue: integer);
+    procedure SetImageIndex(AValue: Integer);
+    procedure SetImages(AValue: TCustomImageList);
+    procedure SetRounding(AValue: TBCRounding);
+    procedure SetRoundingDropDown(AValue: TBCRounding);
+    procedure SetShowCaption(AValue: Boolean);
+    procedure SetStaticButton(const AValue: boolean);
+    procedure SetStyle(const AValue: TBCButtonStyle);
+    procedure SetGlobalOpacity(const AValue: byte);
+    procedure SetTextApplyGlobalOpacity(const AValue: boolean);
+    procedure UpdateSize;
+    procedure OnChangeGlyph(Sender: TObject);
+    procedure OnChangeState(Sender: TObject; AData: PtrInt);
+    procedure ImageListChange(ASender: TObject);
+  protected
+    { Protected declarations }
+    procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
+      WithThemeSpace: boolean); override;
+    class function GetControlClassDefaultSize: TSize; override;
+    procedure Click; override;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
+      X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseEnter; override;
+    procedure MouseLeave; override;
+    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
+    procedure SetEnabled(Value: boolean); override;
+    procedure TextChanged; override;
+  protected
+    // MORA
+    procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
+    function GetActionLinkClass: TControlActionLinkClass; override;
+    procedure Notification(AComponent: TComponent; Operation: TOperation);
+      override;
+    procedure Render(ABGRA: TBGRABitmapEx; AState: TBCButtonState); virtual;
+    procedure RenderState(ABGRA: TBGRABitmapEx; AState: TBCButtonState;
+      const ARect: TRect; ARounding: TBCRounding); virtual;
+    property ClickOffset: Boolean read FClickOffest write SetClickOffset default False;
+    property DropDownArrow: Boolean read FDropDownArrow write SetDropDownArrow default False;
+    property DropDownMenu: TPopupMenu read FDropDownMenu write FDropDownMenu;
+    property DropDownStyle: TBCButtonDropDownStyle read FDropDownStyle write FDropDownStyle default bdsSeparate;
+    property DropDownPosition: TBCButtonDropDownPosition read FDropDownPosition write SetDropDownPosition default bdpLeft;
+    property Images: TCustomImageList read FImages write SetImages;
+    property ImageIndex: Integer read FImageIndex write SetImageIndex default -1;
+    property ShowCaption: Boolean read FShowCaption write SetShowCaption default True;
+  protected
+    {$IFDEF DEBUG}
+    function GetDebugText: String; override;
+    {$ENDIF}
+    function GetStyleExtension: String; override;
+    procedure DrawControl; override;
+    procedure RenderControl; override;
+  protected
+    property AutoSizeExtraVertical: integer read AutoSizeExtraY;
+    property AutoSizeExtraHorizontal: integer read AutoSizeExtraX;
+    property StateNormal: TBCButtonState read FStateNormal write SeTBCButtonStateNormal;
+    property StateHover: TBCButtonState read FStateHover write SeTBCButtonStateHover;
+    property StateClicked: TBCButtonState read FStateClicked write SeTBCButtonStateClicked;
+    property Down: boolean read FDown write SetDown default False;
+    property DropDownWidth: Integer read FDropDownWidth write SetDropDownWidth;
+    property DropDownArrowSize: Integer read FDropDownArrowSize write SetDropDownArrowSize;
+    property FlipArrow: boolean read FFlipArrow write SetFlipArrow default False;
+    property Glyph: TBitmap read FGlyph write SetGlyph;
+    property GlyphMargin: integer read FGlyphMargin write SetGlyphMargin default 5;
+    property Style: TBCButtonStyle read FStyle write SetStyle default bbtButton;
+    property StaticButton: boolean
+      read FStaticButton write SetStaticButton default False;
+    property GlobalOpacity: byte read FGlobalOpacity write SetGlobalOpacity;
+    property Rounding: TBCRounding read FRounding write SetRounding;
+    property RoundingDropDown: TBCRounding read FRoundingDropDown write SetRoundingDropDown;
+    property TextApplyGlobalOpacity: boolean
+      read FTextApplyGlobalOpacity write SetTextApplyGlobalOpacity;
+    property OnAfterRenderBCButton: TOnAfterRenderBCButton
+      read FOnAfterRenderBCButton write FOnAfterRenderBCButton;
+    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
+  public
+    { Public declarations }
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure SetSizeVariables(newDropDownWidth, newDropDownArrowSize,
+      newAutoSizeExtraVertical, newAutoSizeExtraHorizontal: integer);
+    procedure UpdateControl; override; // Called by EndUpdate
+  public
+    { Streaming }
+    procedure SaveToFile(AFileName: string);
+    procedure LoadFromFile(AFileName: string);
+    procedure OnFindClass(Reader: TReader; const AClassName: string;
+      var ComponentClass: TComponentClass);
+  end;
+
+  TBCButton = class(TCustomBCButton)
+  published
+    property Action;
+    property Align;
+    property Anchors;
+    property AssignStyle;
+    property AutoSize;
+    property StateClicked;
+    property StateHover;
+    property StateNormal;
+    property BorderSpacing;
+    property Caption;
+    property Color;
+    property Down;
+    property DropDownWidth;
+    property DropDownArrowSize;
+    property Enabled;
+    property FlipArrow;
+    property GlobalOpacity;
+    property Glyph;
+    property GlyphMargin;
+    property Hint;
+    property OnAfterRenderBCButton;
+    property OnButtonClick;
+    property OnClick;
+    property OnDblClick;
+    property OnMouseDown;
+    property OnMouseEnter;
+    property OnMouseLeave;
+    property OnMouseMove;
+    property OnMouseUp;
+    property ParentColor;
+    property PopupMenu;
+    property Rounding;
+    property RoundingDropDown;
+    property StaticButton;
+    property ShowHint;
+    property Style;
+    property TextApplyGlobalOpacity;
+    property Visible;
+    // MORA
+    property ClickOffset;
+    property DropDownArrow;
+    property DropDownMenu;
+    property DropDownStyle;
+    property DropDownPosition;
+    property Images;
+    property ImageIndex;
+    property ShowCaption;
+  end;
+
+  { TBCButtonActionLink }
+
+  TBCButtonActionLink = class(TControlActionLink)
+  protected
+    procedure AssignClient(AClient: TObject); override;
+    procedure SetChecked(Value: Boolean); override;
+    procedure SetImageIndex(Value: Integer); override;
+  public
+    function IsCheckedLinked: Boolean; override;
+    function IsImageIndexLinked: Boolean; override;
+  end;
+
+procedure Register;
+
+implementation
+
+uses LCLIntf, Math, LCLProc, BGRAPolygon, BCTools, SysUtils, PropEdits, GraphPropEdits;
+
+type
+  TBCButtonImageIndexPropertyEditor = class(TImageIndexPropertyEditor)
+  protected
+    function GetImageList: TCustomImageList; override;
+  end;
+
+function TBCButtonImageIndexPropertyEditor.GetImageList: TCustomImageList;
+var
+  Component: TPersistent;
+begin
+  Component := GetComponent(0);
+  if Component is TCustomBCButton then
+    Result := TCustomBCButton(Component).Images
+  else
+    Result := nil
+end;
+
+procedure Register;
+begin
+  {$I bcbutton_icon.lrs}
+  RegisterComponents('BGRA Controls', [TBCButton]);
+  RegisterPropertyEditor(TypeInfo(Integer), TBCButton,
+    'ImageIndex', TBCButtonImageIndexPropertyEditor);
+end;
+
+{ TBCButtonActionLink }
+
+procedure TBCButtonActionLink.AssignClient(AClient: TObject);
+begin
+  inherited AssignClient(AClient);
+  FClient := AClient as TCustomBCButton;
+end;
+
+procedure TBCButtonActionLink.SetChecked(Value: Boolean);
+begin
+  if IsCheckedLinked then
+    TCustomBCButton(FClient).Down := Value;
+end;
+
+procedure TBCButtonActionLink.SetImageIndex(Value: Integer);
+begin
+  if IsImageIndexLinked then
+    TCustomBCButton(FClient).ImageIndex := Value;
+end;
+
+function TBCButtonActionLink.IsCheckedLinked: Boolean;
+begin
+  Result := inherited IsCheckedLinked and
+    (TCustomBCButton(FClient).Down = (Action as TCustomAction).Checked);
+end;
+
+function TBCButtonActionLink.IsImageIndexLinked: Boolean;
+begin
+  Result := inherited IsImageIndexLinked and
+    (TCustomBCButton(FClient).ImageIndex = (Action as TCustomAction).ImageIndex);
+end;
+
+{ TBCButtonState }
+
+procedure TBCButtonState.SetFontEx(const AValue: TBCFont);
+begin
+  if FFontEx = AValue then
+    exit;
+  FFontEx.Assign(AValue);
+
+  Change;
+end;
+
+procedure TBCButtonState.OnChangeFont(Sender: TObject; AData: PtrInt);
+begin
+  Change(PtrInt(pdUpdateSize));
+end;
+
+procedure TBCButtonState.OnChangeChildProperty(Sender: TObject; AData: PtrInt);
+begin
+  Change(AData);
+end;
+
+procedure TBCButtonState.SetBackground(AValue: TBCBackground);
+begin
+  if FBackground = AValue then Exit;
+  FBackground.Assign(AValue);
+
+  Change;
+end;
+
+procedure TBCButtonState.SetBorder(AValue: TBCBorder);
+begin
+  if FBorder = AValue then Exit;
+  FBorder.Assign(AValue);
+
+  Change;
+end;
+
+constructor TBCButtonState.Create(AControl: TControl);
+begin
+  FBackground := TBCBackground.Create(AControl);
+  FBorder     := TBCBorder.Create(AControl);
+  FFontEx     := TBCFont.Create(AControl);
+
+  FBackground.OnChange := @OnChangeChildProperty;
+  FBorder.OnChange     := @OnChangeChildProperty;
+  FFontEx.OnChange     := @OnChangeFont;
+
+  inherited Create(AControl);
+end;
+
+destructor TBCButtonState.Destroy;
+begin
+  FBackground.Free;
+  FBorder.Free;
+  FFontEx.Free;
+  inherited Destroy;
+end;
+
+procedure TBCButtonState.Assign(Source: TPersistent);
+begin
+  if Source is TBCButtonState then
+  begin
+    FBackground.Assign(TBCButtonState(Source).FBackground);
+    FBorder.Assign(TBCButtonState(Source).FBorder);
+    FFontEx.Assign(TBCButtonState(Source).FFontEx);
+
+    Change(PtrInt(pdUpdateSize));
+  end
+  else
+    inherited Assign(Source);
+end;
+
+{ TCustomBCButton }
+
+procedure TCustomBCButton.AssignDefaultStyle;
+begin
+  FRounding.RoundX := 12;
+  FRounding.RoundY := 12;
+  // Normal
+  with StateNormal do
+  begin
+    Border.Style         := bboNone;
+    FontEx.Color         := RGBToColor(230,230,255);
+    FontEx.Style         := [fsBold];
+    FontEx.Shadow        := True;
+    FontEx.ShadowOffsetX := 1;
+    FontEx.ShadowOffsetY := 1;
+    FontEx.ShadowRadius  := 2;
+    Background.Gradient1EndPercent := 60;
+    Background.Style               := bbsGradient;
+    // Gradient1
+    with Background.Gradient1 do
+    begin
+      EndColor   := RGBToColor(64,64,128);
+      StartColor := RGBToColor(0,0,64);
+    end;
+    // Gradient2
+    with Background.Gradient2 do
+    begin
+      EndColor       := RGBToColor(0,0,64);
+      GradientType   := gtRadial;
+      Point1XPercent := 50;
+      Point1YPercent := 100;
+      Point2YPercent := 0;
+      StartColor     := RGBToColor(64,64,128);
+    end;
+  end;
+  // Hover
+  with StateHover do
+  begin
+    Border.Style         := bboNone;
+    FontEx.Color         := RGBToColor(255,255,255);
+    FontEx.Style         := [fsBold];
+    FontEx.Shadow        := True;
+    FontEx.ShadowOffsetX := 1;
+    FontEx.ShadowOffsetY := 1;
+    FontEx.ShadowRadius  := 2;
+    Background.Gradient1EndPercent := 100;
+    Background.Style               := bbsGradient;
+    // Gradient1
+    with Background.Gradient1 do
+    begin
+      EndColor       := RGBToColor(0,64,128);
+      GradientType   := gtRadial;
+      Point1XPercent := 50;
+      Point1YPercent := 100;
+      Point2YPercent := 0;
+      StartColor     := RGBToColor(0,128,255);
+    end;
+  end;
+  // Clicked
+  with StateClicked do
+  begin
+    Border.Style         := bboNone;
+    FontEx.Color         := RGBToColor(230,230,255);
+    FontEx.Style         := [fsBold];
+    FontEx.Shadow        := True;
+    FontEx.ShadowOffsetX := 1;
+    FontEx.ShadowOffsetY := 1;
+    FontEx.ShadowRadius  := 2;
+    Background.Gradient1EndPercent := 100;
+    Background.Style               := bbsGradient;
+    // Gradient1
+    with Background.Gradient1 do
+    begin
+      EndColor       := RGBToColor(0,0,64);
+      GradientType   := gtRadial;
+      Point1XPercent := 50;
+      Point1YPercent := 100;
+      Point2YPercent := 0;
+      StartColor     := RGBToColor(0,64,128);
+    end;
+  end;
+end;
+
+procedure TCustomBCButton.CalculateGlyphSize(var NeededWidth, NeededHeight: integer);
+begin
+  if Assigned(FGlyph) and not FGlyph.Empty then
+  begin
+    NeededWidth := FGlyph.Width;
+    NeededHeight := FGlyph.Height;
+  end else
+  if Assigned(FImages) then
+  begin
+    NeededWidth := FImages.Width;
+    NeededHeight := FImages.Height;
+  end else
+  begin
+    NeededHeight := 0;
+    NeededWidth := 0;
+  end;
+end;
+
+procedure TCustomBCButton.ConvertToGrayScale(ABGRA: TBGRABitmap);
+var
+  bounds: TRect;
+  px: PBGRAPixel;
+  xb, yb: integer;
+begin
+  bounds := ABGRA.GetImageBounds;
+  if (bounds.Right <= bounds.Left) or (bounds.Bottom <= Bounds.Top) then
+    exit;
+
+  for yb := bounds.Top to bounds.bottom - 1 do
+  begin
+    px := ABGRA.scanline[yb] + bounds.left;
+    for xb := bounds.left to bounds.right - 1 do
+    begin
+      px^ := BGRAToGrayscale(px^);
+      Inc(px);
+    end;
+  end;
+  ABGRA.InvalidateBitmap;
+end;
+
+procedure TCustomBCButton.RenderAll(ANow: Boolean);
+begin
+  if (csCreating in FControlState) or IsUpdating or (FBGRANormal=nil) then
+    Exit;
+
+  if ANow then
+  begin
+    Render(FBGRANormal, FStateNormal);
+    Render(FBGRAHover, FStateHover);
+    Render(FBGRAClick, FStateClicked);
+  end else
+  begin
+    FBGRANormal.NeedRender := True;
+    FBGRAHover.NeedRender := True;
+    FBGRAClick.NeedRender := True;
+  end;
+end;
+
+function TCustomBCButton.GetButtonRect: TRect;
+begin
+  Result := GetClientRect;
+  if FStyle=bbtDropDown then
+    case FDropDownPosition of
+      bdpBottom:
+        Dec(Result.Bottom, GetDropDownWidth(False));
+    else
+      // bdpLeft:
+      Dec(Result.Right, GetDropDownWidth(False));
+    end;
+end;
+
+function TCustomBCButton.GetDropDownWidth(AFull: boolean): integer;
+begin
+  Result := FDropDownWidth + (ifthen(AFull, 2, 1) * FStateNormal.FBorder.Width);
+end;
+
+function TCustomBCButton.GetDropDownRect(AFull: Boolean): TRect;
+begin
+  Result := GetClientRect;
+  case FDropDownPosition of
+    bdpBottom:
+      Result.Top := Result.Bottom - GetDropDownWidth(AFull);
+  else
+    // bdpLeft:
+    Result.Left := Result.Right - GetDropDownWidth(AFull);
+  end;
+end;
+
+procedure TCustomBCButton.Render(ABGRA: TBGRABitmapEx;
+  AState: TBCButtonState);
+var
+  r,r_a: TRect;
+
+  { TODO: Create customizable glyph position by creating TBCGlyph type
+          and method in BCTools which render it }
+  procedure _RenderGlyph;
+  var
+    w, h, t, l: Integer;
+    g: TBGRABitmap;
+    bitmap: TBitmap;
+  begin
+    // MORA: getting image to draw
+    if Assigned(FGlyph) and not FGlyph.Empty then
+      bitmap := FGlyph
+    else
+    if Assigned(FImages) and (FImageIndex > -1) and (FImageIndex < FImages.Count) then
+    begin
+      bitmap := TBitmap.Create;
+      FImages.GetBitmap(FImageIndex, bitmap)
+    end else
+      bitmap := nil;
+
+    if (bitmap<>nil) and (not bitmap.Empty) then
+    begin
+      if not FShowCaption then
+      begin
+        w := 0;
+        h := 0;
+      end else
+        CalculateTextSize(Caption,AState.FontEx,w,h);
+      l := r.Right - Round(((r.Right-r.Left) + w + bitmap.Width)/2);
+      t := r.Bottom - Round(((r.Bottom-r.Top) + bitmap.Height) / 2);
+      g := TBGRABitmap.Create(bitmap);
+      ABGRA.BlendImage(l,t,g,boLinearBlend);
+      g.Free;
+      Inc(r.Left,l+bitmap.Width+FGlyphMargin);
+    end;
+
+    if bitmap <> FGlyph then
+      bitmap.Free;
+  end;
+
+begin
+  if (csCreating in FControlState) or IsUpdating then
+    Exit;
+
+  ABGRA.NeedRender := False;
+
+  { Refreshing size }
+  ABGRA.SetSize(Width, Height);
+
+  { Calculating rect }
+  r   := GetButtonRect;
+  CalculateBorderRect(AState.Border,r);
+
+  if FStyle = bbtDropDown then
+  begin
+    r_a := GetDropDownRect;
+    CalculateBorderRect(AState.Border,r_a);
+  end;
+
+  { Clearing previous paint }
+  ABGRA.Fill(BGRAPixelTransparent);
+  { Basic body }
+  RenderState(ABGRA, AState, r, FRounding);
+  if FStyle = bbtDropDown then
+  begin
+    RenderState(ABGRA, AState, r_a, FRoundingDropDown);
+    // Click offset for arrow
+    if FClickOffest and (AState = FStateClicked) then
+    begin
+      Inc(r_a.Left,2);
+      Inc(r_a.Top,2);
+    end;
+
+    if FFlipArrow then
+      RenderArrow(TBGRABitmap(ABGRA),r_a,FDropDownArrowSize,badUp,AState.FontEx.Color)
+    else
+      RenderArrow(TBGRABitmap(ABGRA),r_a,FDropDownArrowSize,badDown,AState.FontEx.Color);
+  end;
+
+  // Click offset for text and glyph
+  if FClickOffest and (AState = FStateClicked) then
+  begin
+    Inc(r.Left,2);
+    Inc(r.Top,2);
+  end;
+
+  // DropDown arrow
+  if FDropDownArrow and (FStyle <> bbtDropDown) then
+  begin
+    r_a := r;
+    r_a.Left := r_a.Right - FDropDownWidth;
+    if FFlipArrow then
+      RenderArrow(TBGRABitmap(ABGRA),r_a,FDropDownArrowSize,badUp,AState.FontEx.Color)
+    else
+      RenderArrow(TBGRABitmap(ABGRA),r_a,FDropDownArrowSize,badDown,AState.FontEx.Color);
+    Dec(R.Right, FDropDownWidth);
+  end;
+
+  if FTextApplyGlobalOpacity then
+  begin
+    { Drawing text }
+    _RenderGlyph;
+    if FShowCaption then
+      RenderText(r,AState.FontEx,Self.Caption,TBGRABitmap(ABGRA));
+
+    { Set global opacity }
+    ABGRA.ApplyGlobalOpacity(FGlobalOpacity);
+  end
+  else
+  begin
+    { Set global opacity }
+    ABGRA.ApplyGlobalOpacity(FGlobalOpacity);
+    { Drawing text }
+    _RenderGlyph;
+    if FShowCaption then
+      RenderText(r,AState.FontEx,Self.Caption,TBGRABitmap(ABGRA));
+  end;
+
+  { Convert to gray if not enabled }
+  if not Enabled then
+    ConvertToGrayScale(ABGRA);
+
+  if Assigned(FOnAfterRenderBCButton) then
+    FOnAfterRenderBCButton(Self, ABGRA, AState, r);
+
+  {$IFDEF DEBUG}
+  FRenderCount += 1;
+  {$ENDIF}
+end;
+
+procedure TCustomBCButton.RenderState(ABGRA: TBGRABitmapEx;
+  AState: TBCButtonState; const ARect: TRect; ARounding: TBCRounding);
+begin
+  RenderBackground(ARect, AState.FBackground, TBGRABitmap(ABGRA), ARounding);
+  RenderBorder(ARect, AState.FBorder, TBGRABitmap(ABGRA), ARounding);
+end;
+
+procedure TCustomBCButton.OnChangeGlyph(Sender: TObject);
+begin
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.OnChangeState(Sender: TObject; AData: PtrInt);
+begin
+  RenderControl;
+  if TBCButtonPropertyData(AData)=pdUpdateSize then
+    UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.ImageListChange(ASender: TObject);
+begin
+  if ASender = Images then
+  begin
+    RenderControl;
+    Invalidate;
+  end;
+end;
+
+procedure TCustomBCButton.SeTBCButtonStateClicked(const AValue: TBCButtonState);
+begin
+  if FStateClicked = AValue then
+    exit;
+  FStateClicked.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SeTBCButtonStateHover(const AValue: TBCButtonState);
+begin
+  if FStateHover = AValue then
+    exit;
+  FStateHover.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SeTBCButtonStateNormal(const AValue: TBCButtonState);
+begin
+  if FStateNormal = AValue then
+    exit;
+  FStateNormal.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetClickOffset(AValue: Boolean);
+begin
+  if FClickOffest = AValue then Exit;
+  FClickOffest := AValue;
+  RenderControl;
+end;
+
+procedure TCustomBCButton.SetDown(AValue: boolean);
+begin
+  if FDown = AValue then
+    exit;
+  FDown := AValue;
+  if FDown
+  then FButtonState := msClicked
+  else FButtonState := msNone;
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetDropDownArrow(AValue: Boolean);
+begin
+  if FDropDownArrow = AValue then Exit;
+  FDropDownArrow := AValue;
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetDropDownArrowSize(AValue: Integer);
+begin
+  if FDropDownArrowSize = AValue then Exit;
+  FDropDownArrowSize := AValue;
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetDropDownPosition(AValue: TBCButtonDropDownPosition
+  );
+begin
+  if FDropDownPosition = AValue then Exit;
+  FDropDownPosition := AValue;
+
+  if FStyle <> bbtDropDown then Exit;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetDropDownWidth(AValue: Integer);
+begin
+  if FDropDownWidth = AValue then Exit;
+  FDropDownWidth := AValue;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetFlipArrow(AValue: boolean);
+begin
+  if FFlipArrow = AValue then
+    Exit;
+  FFlipArrow := AValue;
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetGlyph(const AValue: TBitmap);
+begin
+  if (FGlyph <> nil) and (FGlyph = AValue) then
+    exit;
+
+  FGlyph.Assign(AValue);
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetGlyphMargin(const AValue: integer);
+begin
+  if FGlyphMargin = AValue then
+    exit;
+  FGlyphMargin := AValue;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetImageIndex(AValue: Integer);
+begin
+  if FImageIndex = AValue then Exit;
+  FImageIndex := AValue;
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetImages(AValue: TCustomImageList);
+begin
+  if FImages = AValue then Exit;
+  FImages := AValue;
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetRounding(AValue: TBCRounding);
+begin
+  if FRounding = AValue then Exit;
+  FRounding.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetRoundingDropDown(AValue: TBCRounding);
+begin
+  if FRoundingDropDown = AValue then Exit;
+  FRoundingDropDown.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetShowCaption(AValue: Boolean);
+begin
+  if FShowCaption = AValue then Exit;
+  FShowCaption := AValue;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetStaticButton(const AValue: boolean);
+begin
+  if FStaticButton = AValue then
+    exit;
+  FStaticButton := AValue;
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetStyle(const AValue: TBCButtonStyle);
+begin
+  if FStyle = AValue then
+    exit;
+  FStyle := AValue;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.UpdateSize;
+begin
+  InvalidatePreferredSize;
+  AdjustSize;
+end;
+
+procedure TCustomBCButton.CalculatePreferredSize(
+  var PreferredWidth, PreferredHeight: integer; WithThemeSpace: boolean);
+var
+  AWidth: integer;
+  gh: integer = 0;
+  gw: integer = 0;
+begin
+  if (Parent = nil) or (not Parent.HandleAllocated) then
+    Exit;
+  if WidthIsAnchored then
+    AWidth := Width
+  else
+    AWidth := 10000;
+
+  PreferredWidth := 0;
+  PreferredHeight := 0;
+  if FShowCaption then
+    CalculateTextSize(Caption, FStateNormal.FontEx, PreferredWidth, PreferredHeight);
+
+  // Extra pixels for DropDown
+  if Style = bbtDropDown then
+    if FDropDownPosition in [bdpBottom] then
+      Inc(PreferredHeight, GetDropDownWidth)
+    else
+      Inc(PreferredWidth, GetDropDownWidth);
+
+  if (Style = bbtButton) and FDropDownArrow then
+      Inc(PreferredWidth, FDropDownArrowSize);// GetDropDownWidth);
+
+  CalculateGlyphSize(gw, gh);
+
+  //if (FGlyph <> nil) and (not FGlyph.Empty) then
+  if (gw > 0) and (gh > 0) then
+  begin
+    //if Caption = '' then
+    if PreferredWidth = 0 then
+    begin
+      Inc(PreferredWidth, gw{ - AutoSizeExtraY * 2});
+      Inc(PreferredHeight, gh);
+    end
+    else
+    begin
+      Inc(PreferredWidth, gw + FGlyphMargin);
+      if gh > PreferredHeight then
+        PreferredHeight := gh;
+    end;
+  end;
+
+  // Extra pixels for AutoSize
+  Inc(PreferredWidth, AutoSizeExtraX);
+  Inc(PreferredHeight, AutoSizeExtraY);
+end;
+
+class function TCustomBCButton.GetControlClassDefaultSize: TSize;
+begin
+  Result.CX := 123;
+  Result.CY := 33;
+end;
+
+procedure TCustomBCButton.Click;
+begin
+  if (FActiveButt = bbtDropDown) and Assigned(FOnButtonClick) then
+  begin
+    FOnButtonClick(Self);
+    Exit;
+  end;
+  inherited Click;
+end;
+
+procedure TCustomBCButton.DropDownClosed(Sender: TObject);
+begin
+  if Assigned(FSaveDropDownClosed) then
+    FSaveDropDownClosed(Sender);
+  if Assigned(FDropDownMenu) then
+    FDropDownMenu.OnClose := FSaveDropDownClosed;
+
+  // MORA: DropDownMenu is still visible if mouse is over control
+  FDropDownMenuVisible := PtInRect(ClientRect, ScreenToClient(Mouse.CursorPos));
+end;
+
+procedure TCustomBCButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
+  X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if csDesigning in ComponentState then
+    exit;
+
+  if (Button = mbLeft) and Enabled {and (not (FButtonState = msClicked)) }then
+  begin
+    case FActiveButt of
+      bbtButton:
+        if not (FButtonState=msClicked) then
+        begin
+          FButtonState     := msClicked;
+          if FDropDownStyle = bdsCommon then
+            FDownButtonState := msClicked
+          else
+            FDownButtonState := msNone;
+          Invalidate;
+        end;
+      bbtDropDown:
+        if not (FDownButtonState=msClicked) then
+        begin
+          if FDropDownStyle = bdsCommon then
+            FButtonState     := msClicked
+          else
+            FButtonState     := msNone;
+          FDownButtonState := msClicked;
+          Invalidate;
+        end;
+    end;
+    // Old
+    {FButtonState := msClicked;
+    Invalidate;}
+
+    // MORA: Show DropDown menu
+    if FDropDownMenuVisible then
+      FDropDownMenuVisible := False // Prevent redropping
+    else
+    if ((FActiveButt = bbtDropDown) or (FStyle = bbtButton)) and (FDropDownMenu <> nil) and Enabled then
+      with ClientToScreen(Point(0, Height)) do
+      begin
+        // normal button
+        if FStyle = bbtButton then
+        begin
+          x := x + Width * Integer(FDropDownMenu.Alignment = paRight);
+          if FFlipArrow then
+            y -= Height;
+        end else
+        // dropdown button
+        begin
+          if FDropDownPosition = bdpBottom then
+          begin
+            x := x + Width * Integer(FDropDownMenu.Alignment = paRight);
+            if FFlipArrow then
+              y -= (FDropDownWidth + (FStateNormal.FBorder.Width * 2));
+          end else
+          begin
+            if FFlipArrow then
+              y -= Height;
+            if FDropDownStyle = bdsSeparate then
+              x := x + Width - (FDropDownWidth + (FStateNormal.FBorder.Width * 2)) * Integer(FDropDownMenu.Alignment <> paRight)
+            else
+              x := x + Width * Integer(FDropDownMenu.Alignment = paRight);
+          end
+        end;
+
+        FDropDownMenuVisible := True;
+        FSaveDropDownClosed := FDropDownMenu.OnClose;
+        FDropDownMenu.OnClose := @DropDownClosed;
+        FDropDownMenu.PopUp(x, y);
+      end;
+  end;
+end;
+
+procedure TCustomBCButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
+  X, Y: integer);
+var
+  p: TPoint;
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+  if csDesigning in ComponentState then
+    exit;
+
+  if (Button = mbLeft) and Enabled {and (FButtonState = msClicked)} then
+  begin
+    case FActiveButt of
+      bbtButton:
+        if FButtonState=msClicked then
+        begin
+          FButtonState     := msHover;
+          if FDropDownStyle = bdsCommon then
+            FDownButtonState := msHover
+          else
+            FDownButtonState := msNone;
+          Invalidate;
+        end;
+      bbtDropDown:
+        if FDownButtonState = msClicked then
+        begin
+          FDownButtonState := msHover;
+          if FDropDownStyle = bdsCommon then
+            FButtonState     := msHover
+          else
+            FButtonState     := msNone;
+          Invalidate;
+        end;
+    end;
+    // Old
+    {FButtonState := msHover;
+    Invalidate;}
+  end;
+
+  //if (FActiveButt = bbtDropDown) and (PopupMenu <> nil) and Enabled then
+  //begin
+  //  if FFlipArrow then
+  //    p := ClientToScreen(Point(Width - FDropDownWidth - (FStateNormal.FBorder.Width * 2),
+  //      {PopupMenu.Height} -1))
+  //  else
+  //    p := ClientToScreen(Point(Width - FDropDownWidth - (FStateNormal.FBorder.Width * 2), Height + 1));
+  //
+  //  PopupMenu.PopUp(p.x, p.y);
+  //end;
+end;
+
+procedure TCustomBCButton.MouseEnter;
+begin
+  if csDesigning in ComponentState then
+    exit;
+  case FActiveButt of
+    bbtButton:
+      begin
+        if FDown
+        then FButtonState := msClicked
+        else FButtonState := msHover;
+
+        if FDropDownStyle = bdsSeparate then
+          FDownButtonState  := msNone
+        else
+          FDownButtonState  := msHover
+      end;
+    bbtDropDown:
+      begin
+        if FDown
+        then FButtonState := msClicked
+        else
+        if FDropDownStyle = bdsSeparate then
+          FButtonState := msNone
+        else
+          FButtonState := msHover;
+        FDownButtonState  := msHover
+      end;
+  end;
+  Invalidate;
+  // Old
+  {FButtonState := msHover;
+  Invalidate;}
+  inherited MouseEnter;
+end;
+
+procedure TCustomBCButton.MouseLeave;
+begin
+  if csDesigning in ComponentState then
+    exit;
+  if FDown then
+  begin
+    FButtonState := msClicked;
+    FActiveButt := bbtButton;
+  end
+  else
+    FButtonState := msNone;
+  FDownButtonState  := msNone;
+  Invalidate;
+  inherited MouseLeave;
+end;
+
+procedure TCustomBCButton.MouseMove(Shift: TShiftState; X, Y: integer);
+
+  function IsOverDropDown: Boolean;
+  begin
+    with GetButtonRect do
+      case FDropDownPosition of
+        bdpBottom:
+          Result := Y > Bottom;
+      else
+        Result := X > GetButtonRect.Right;
+      end;
+  end;
+
+begin
+  inherited MouseMove(Shift, X, Y);
+
+  if FStyle=bbtButton then
+    FActiveButt := bbtButton
+  else
+  begin
+    // Calling invalidate only when active button changed. Otherwise, we leave
+    // this for LCL. This reduce paint call
+    if (FActiveButt=bbtButton) and IsOverDropDown then
+    begin
+      FActiveButt      := bbtDropDown;
+      if FDropDownStyle <> bdsCommon then // Don't need invalidating
+      begin
+        FDownButtonState := msHover;
+        if FDown
+        then FButtonState := msClicked
+        else FButtonState := msNone;
+        Invalidate;
+      end;
+    end else
+    if (FActiveButt=bbtDropDown) and not IsOverDropDown then
+    begin
+      FActiveButt      := bbtButton;
+      if FDropDownStyle <> bdsCommon then // Don't need invalidating
+      begin
+        if FDown
+        then FButtonState := msClicked
+        else FButtonState := msHover;
+        FDownButtonState := msNone;
+        Invalidate;
+      end;
+    end;
+  end;
+end;
+
+procedure TCustomBCButton.SetEnabled(Value: boolean);
+begin
+  inherited SetEnabled(Value);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.TextChanged;
+begin
+  inherited TextChanged;
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.ActionChange(Sender: TObject; CheckDefaults: Boolean);
+var
+  NewAction: TCustomAction;
+begin
+  inherited ActionChange(Sender, CheckDefaults);
+  if Sender is TCustomAction then
+  begin
+    NewAction := TCustomAction(Sender);
+    if (not CheckDefaults) or (not Down) then
+      Down := NewAction.Checked;
+    if (not CheckDefaults) or (ImageIndex<0) then
+      ImageIndex := NewAction.ImageIndex;
+  end;
+end;
+
+function TCustomBCButton.GetActionLinkClass: TControlActionLinkClass;
+begin
+  Result := TBCButtonActionLink;
+end;
+
+procedure TCustomBCButton.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  if (AComponent = FImages) and (Operation = opRemove) then
+    Images := nil;
+end;
+
+procedure TCustomBCButton.UpdateControl;
+begin
+  RenderControl;
+  inherited UpdateControl; // indalidate
+end;
+
+procedure TCustomBCButton.SaveToFile(AFileName: string);
+var
+  AStream: TMemoryStream;
+begin
+  AStream := TMemoryStream.Create;
+  try
+    WriteComponentAsTextToStream(AStream, Self);
+    AStream.SaveToFile(AFileName);
+  finally
+    AStream.Free;
+  end;
+end;
+
+procedure TCustomBCButton.LoadFromFile(AFileName: string);
+var
+  AStream: TMemoryStream;
+begin
+  AStream := TMemoryStream.Create;
+  try
+    AStream.LoadFromFile(AFileName);
+    ReadComponentFromTextStream(AStream, TComponent(Self), @OnFindClass);
+  finally
+    AStream.Free;
+  end;
+end;
+
+procedure TCustomBCButton.OnFindClass(Reader: TReader;
+  const AClassName: string; var ComponentClass: TComponentClass);
+begin
+  if CompareText(AClassName, 'TCustomBCButton') = 0 then
+    ComponentClass := TCustomBCButton
+  else if CompareText(AClassName, 'TBCButton') = 0 then
+    ComponentClass := TBCButton;
+end;
+
+{$IFDEF DEBUG}
+function TCustomBCButton.GetDebugText: String;
+begin
+  Result := 'R: '+IntToStr(FRenderCount);
+end;
+{$ENDIF}
+
+procedure TCustomBCButton.DrawControl;
+var
+  bgra: TBGRABitmapEx;
+begin
+
+  // If style is without dropdown button or state of each button
+  // is the same (possible only for msNone) or static button then
+  // we can draw whole BGRABitmap
+  if (FStyle=bbtButton) or (FButtonState=FDownButtonState) or FStaticButton
+  then
+  begin
+    // Main button
+    if FStaticButton then
+      bgra := FBGRANormal
+    else
+    if FDown then
+      bgra := FBGRAClick
+    else
+      case FButtonState of
+        msNone: bgra := FBGRANormal;
+        msHover: bgra := FBGRAHover;
+        msClicked: bgra := FBGRAClick;
+      end;
+    if bgra.NeedRender then
+      Render(bgra,TBCButtonState(bgra.CustomData));
+    bgra.Draw(Self.Canvas, 0, 0, False);
+  end
+  // Otherwise we must draw part of state for each button
+  else
+  begin
+    // The active button must be draw as last because right edge of button and
+    // left edge of dropdown are overlapping each other, so we must draw edge
+    // for current state of active button
+    case FActiveButt of
+      bbtButton:
+        begin
+          // Drop down button
+          case FDownButtonState of
+            msNone: bgra := FBGRANormal;
+            msHover: bgra := FBGRAHover;
+            msClicked: bgra := FBGRAClick;
+          end;
+          if bgra.NeedRender then
+            Render(bgra,TBCButtonState(bgra.CustomData));
+          bgra.DrawPart(GetDropDownRect,Self.Canvas,GetDropDownRect.Left,GetDropDownRect.Top,False);
+          // Main button
+          if FDown then
+            bgra := FBGRAClick
+          else
+            case FButtonState of
+              msNone: bgra := FBGRANormal;
+              msHover: bgra := FBGRAHover;
+              msClicked: bgra := FBGRAClick;
+            end;
+          if bgra.NeedRender then
+            Render(bgra,TBCButtonState(bgra.CustomData));
+          bgra.DrawPart(GetButtonRect, Self.Canvas, 0, 0, False);
+        end;
+      bbtDropDown:
+        begin
+          // Main button
+          if FDown then
+            bgra := FBGRAClick
+          else
+            case FButtonState of
+              msNone: bgra := FBGRANormal;
+              msHover: bgra := FBGRAHover;
+              msClicked: bgra := FBGRAClick;
+            end;
+          if bgra.NeedRender then
+            Render(bgra,TBCButtonState(bgra.CustomData));
+          bgra.DrawPart(GetButtonRect, Self.Canvas, 0, 0, False);
+          // Drop down button
+          case FDownButtonState of
+            msNone: bgra := FBGRANormal;
+            msHover: bgra := FBGRAHover;
+            msClicked: bgra := FBGRAClick;
+          end;
+          if bgra.NeedRender then
+            Render(bgra,TBCButtonState(bgra.CustomData));
+          bgra.DrawPart(GetDropDownRect,Self.Canvas,GetDropDownRect.Left,GetDropDownRect.Top,False);
+        end;
+    end;
+  end;
+end;
+
+procedure TCustomBCButton.RenderControl;
+begin
+  inherited RenderControl;
+  RenderAll;
+end;
+
+procedure TCustomBCButton.SetGlobalOpacity(const AValue: byte);
+begin
+  if FGlobalOpacity = AValue then
+    exit;
+  FGlobalOpacity := AValue;
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCButton.SetTextApplyGlobalOpacity(const AValue: boolean);
+begin
+  if FTextApplyGlobalOpacity = AValue then
+    exit;
+  FTextApplyGlobalOpacity := AValue;
+
+  RenderControl;
+  Invalidate;
+end;
+
+constructor TCustomBCButton.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  {$IFDEF DEBUG}
+  FRenderCount := 0;
+  {$ENDIF}
+  DisableAutoSizing;
+  Include(FControlState, csCreating);
+  //{$IFDEF WINDOWS}
+  // default sizes under different dpi settings
+  //SetSizeVariables(ScaleX(8,96), ScaleX(16,96), ScaleY(8,96), ScaleX(24,96));
+  //{$ELSE}
+  // default sizes
+  SetSizeVariables(16, 8, 8, 24);
+  //{$ENDIF}
+  BeginUpdate;
+  try
+    with GetControlClassDefaultSize do
+      SetInitialBounds(0, 0, CX, CY);
+    ControlStyle := ControlStyle + [csAcceptsControls];
+    FBGRANormal := TBGRABitmapEx.Create(Width, Height, BGRAPixelTransparent);
+    FBGRAHover := TBGRABitmapEx.Create(Width, Height, BGRAPixelTransparent);
+    FBGRAClick := TBGRABitmapEx.Create(Width, Height, BGRAPixelTransparent);
+
+    ParentColor := False;
+    Color := clNone;
+
+    FStateNormal           := TBCButtonState.Create(Self);
+    FStateHover            := TBCButtonState.Create(Self);
+    FStateClicked          := TBCButtonState.Create(Self);
+    FStateNormal.OnChange  := @OnChangeState;
+    FStateHover.OnChange   := @OnChangeState;
+    FStateClicked.OnChange := @OnChangeState;
+
+    FRounding              := TBCRounding.Create(Self);
+    FRounding.OnChange     := @OnChangeState;
+
+    FRoundingDropDown      := TBCRounding.Create(Self);
+    FRoundingDropDown.OnChange := @OnChangeState;
+
+    { Connecting bitmaps with states property to easy call and access }
+    FBGRANormal.CustomData := PtrInt(FStateNormal);
+    FBGRAHover.CustomData  := PtrInt(FStateHover);
+    FBGRAClick.CustomData  := PtrInt(FStateClicked);
+
+    FButtonState := msNone;
+    FDownButtonState := msNone;
+    FFlipArrow := False;
+    FGlyph := TBitmap.Create;
+    FGlyph.OnChange := @OnChangeGlyph;
+    FGlyphMargin := 5;
+    FStyle := bbtButton;
+    FStaticButton := False;
+    FActiveButt := bbtButton;
+    FGlobalOpacity := 255;
+    FTextApplyGlobalOpacity := False;
+    //FStates := [];
+    FDown := False;
+
+    { Default style }
+    AssignDefaultStyle;
+
+    FImageChangeLink := TChangeLink.Create;
+    FImageChangeLink.OnChange := @ImageListChange;
+    FImageIndex := -1;
+
+    FShowCaption := True;
+  finally
+    Exclude(FControlState, csCreating);
+    EnableAutoSizing;
+    EndUpdate;
+  end;
+end;
+
+destructor TCustomBCButton.Destroy;
+begin
+  FImageChangeLink.Free;
+  FStateNormal.Free;
+  FStateHover.Free;
+  FStateClicked.Free;
+  FBGRANormal.Free;
+  FBGRAHover.Free;
+  FBGRAClick.Free;
+  FreeThenNil(FGlyph);
+  FRounding.Free;
+  FRoundingDropDown.Free;
+  inherited Destroy;
+end;
+
+procedure TCustomBCButton.Assign(Source: TPersistent);
+begin
+  if Source is TCustomBCButton then
+  begin
+    Glyph := TCustomBCButton(Source).Glyph;
+    FGlyphMargin := TCustomBCButton(Source).FGlyphMargin;
+    FStyle := TCustomBCButton(Source).FStyle;
+    FFlipArrow := TCustomBCButton(Source).FFlipArrow;
+    FStaticButton := TCustomBCButton(Source).FStaticButton;
+    FGlobalOpacity := TCustomBCButton(Source).FGlobalOpacity;
+    FTextApplyGlobalOpacity := TCustomBCButton(Source).FTextApplyGlobalOpacity;
+    FStateNormal.Assign(TCustomBCButton(Source).FStateNormal);
+    FStateHover.Assign(TCustomBCButton(Source).FStateHover);
+    FStateClicked.Assign(TCustomBCButton(Source).FStateClicked);
+    FDropDownArrowSize := TCustomBCButton(Source).FDropDownArrowSize;
+    FDropDownWidth := TCustomBCButton(Source).FDropDownWidth;
+    AutoSizeExtraX := TCustomBCButton(Source).AutoSizeExtraX;
+    AutoSizeExtraY := TCustomBCButton(Source).AutoSizeExtraY;
+    FDown := TCustomBCButton(Source).FDown;
+    FRounding.Assign(TCustomBCButton(Source).FRounding);
+    FRoundingDropDown.Assign(TCustomBCButton(Source).FRoundingDropDown);
+
+    RenderControl;
+    Invalidate;
+    UpdateSize;
+  end
+  else
+    inherited Assign(Source);
+end;
+
+procedure TCustomBCButton.SetSizeVariables(newDropDownWidth, newDropDownArrowSize,
+  newAutoSizeExtraVertical, newAutoSizeExtraHorizontal: integer);
+begin
+  FDropDownArrowSize := newDropDownArrowSize;
+  FDropDownWidth     := newDropDownWidth;
+  AutoSizeExtraY     := newAutoSizeExtraVertical;
+  AutoSizeExtraX     := newAutoSizeExtraHorizontal;
+
+  if csCreating in ControlState then
+    Exit;
+
+  RenderControl;
+  UpdateSize;
+  Invalidate;
+end;
+
+function TCustomBCButton.GetStyleExtension: String;
+begin
+  Result := 'bcbtn';
+end;
+
+end.

+ 31 - 0
bcbutton_icon.lrs

@@ -0,0 +1,31 @@
+LazarusResources.Add('tbcbutton','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#2#139'IDATx^'#237'UMKUQ'#20']'#251#156#243#204#7#129#137'QA!'#4'Q'#163#168
+  +'h'#212#160#31#208'/'#136#192#240'Q'#208#208'FE'#10'j'#13#210'A$(AR'#8'ZH'
+  +#244#23'$h\'#163#160#6'FI5'#9'"'#164#30#154#239#189's'#207'G{'#159'{'#159#151
+  +#135#209' q'#16#184'`s'#246#217#251#222#181#246#199#133'K!'#4#16#17'v'#10#20
+  +'c'#196'NB'#177#253#223#2#244'y'#229'}|'#246#226#13#222'}'#252#6'e4"'#254'>'
+  +#178#224'='#144#158'!t"'#130'H%'#211'F'#225#202#133#179'8v'#228#16#204#212
+  +#243'W'#168#238#239#199#169's'#199#209#180#0#169'm,<F("8'#31#176#248'r'#25'7'
+  +'.'#246#193','#255#168'`'#186'v'#30#7'{'#21#164'8'#218#202'/'#241#4#165#242
+  +'|'#8#226#255#145#31#129#173#186#7#184#245#240'''V'#190#214'a'#26'6'#162#167
+  +#219#161#183'[!'#132#188#2#160#156'B`6'#165#187'J'#18#159#129't'#5#8'n'#203
+  +#148'b'#16#1#15'm'#12'|'#8')o'#132#192'zp@'#161#229'B)'#0'J'#21'U'#187#12#6
+  +'.'#215' Xx:'#15'0'#249' '#223#31#207#205'q'#158#197#203'V'#248#30'Y@'#161
+  +#170'u'#26#19#17#193'd'#158#131'b'#25#224'l'#217#186#247#14'Zk'#12'\'#173'av'
+  +'v'#14#2'!^X'#152#135#192'('#13#197#182#177#225#249'$!g'#203#199'G]'#128#11
+  +'QJ'#132#241'B'#30#1#199#167'sqS '#203#188#200'@'#208'hX'#180'Q'#175#231#254
+  +#218#154#197#208#208'5'#204#204'<'#130'@:'#137#16#129#184#185'''q'#140#4'dL'
+  +#205'V'#147'MZ'#166'B C'#129#148'k#sI '#145#223#159'z'#144#238'!'#148#31#135
+  +'s'#30#177#167#146#132' '#29#132#162#173#204':'#180'Z'#30#186#16#176#165#0
+  +#199'K'#191#177#209'b'#146#0'cT'#242#11'l'#238'"c'#129#224#9'9?'#193#200'h<'
+  +#223'l'#203'v'#8'DV'#21#140#141'N'#226#246#248#205#220#31#155#132#181'6'#145
+  +'OLLcd'#228'z'#138#181'A'#164#184's'''#11#22#206'|'#201'^.b'#200'w'#16#21#18
+  +#8'RE'#132'`x'#248'.'#156#188#232#0#163'5'#147#222#227#234#155',0'#137#204#6
+  +'h'#163#145#30'-8'#130#7#188#11'il&*'#5'c4'#236#175'&l'#217'A'#199#167'G'#28
+  +'#"'#206'7'#145#17#229#177#246#169#20#147#150'#'#228#209#138#12#200#152#180#7
+  +#179#175#210#192#147#165'O8'#176#247#176'tR,'#139#240'o'#136'I'#244#245#23
+  +#139#213#239#171#232#235'='#10'3~'#233'$'#238',.'#225#237#135'u'#217#20#182
+  +#11#18#163#136#209#193#211'8s'#162#159'v'#127'8'#187#2#219#199'o''+w'#167#205
+  +#252#27#230#0#0#0#0'IEND'#174'B`'#130
+]);

+ 210 - 0
bceffect.pas

@@ -0,0 +1,210 @@
+unit BCEffect;
+
+{$mode objfpc}{$H+}
+{$modeswitch advancedrecords}
+
+interface
+
+uses
+  Classes, SysUtils, LCLProc, BGRABitmapTypes;
+
+{-- Fading --}
+
+type
+  TFadingMode = (fmSuspended, fmFadeIn, fmFadeOut, fmFadeInCycle, fmFadeOutCycle, fmFadeInOut, fmFadeOutIn);
+
+const
+  FadingModeStr: array[TFadingMode] of string = ('Suspended', 'Fade In', 'Fade Out', 'Fade In Cycle','Fade Out Cycle', 'Fade In Out', 'Fade Out In');
+
+function StrToTFadingMode(const s: ansistring): TFadingMode;
+procedure FadingModeStrList(s: TStrings);
+
+type
+
+  { TFading }
+
+  TFading = record
+  private
+    FAlpha: byte;
+    FMode: TFadingMode;
+    FAlphaStep: byte;
+    FDuration: integer;
+    FPrevDate: TDateTime;
+    FElapsedMsAccumulator: integer;
+  public
+    procedure SetFAlpha(AValue: byte);
+    procedure SetFMode(AValue: TFadingMode);
+    procedure SetFAlphaStep(AValue: byte);
+    procedure SetFDuration(AValue: integer);
+  public
+    function Execute(AStepCount: integer= 1): byte; // execute and return new alpha
+    function Reset: byte;   // reset and return new alpha
+    procedure PutImage(ADestination: TBGRACustomBitmap; AX,AY: integer; ASource: TBGRACustomBitmap);
+    procedure FillRect(ADestination: TBGRACustomBitmap; ARect: TRect; AColor: TBGRAPixel);
+  public
+    property Alpha: byte read FAlpha write SetFAlpha;
+    property Mode: TFadingMode read FMode write SetFMode;
+    property Step: byte read FAlphaStep write SetFAlphaStep;
+    property Duration: integer read FDuration write SetFDuration;
+  end;
+
+{-- Fading --}
+
+implementation
+
+{-- Fading --}
+
+function StrToTFadingMode(const s: ansistring): TFadingMode;
+var
+  fm: TFadingMode;
+  ls: ansistring;
+begin
+  ls := UTF8LowerCase(s);
+  for fm := low(TFadingMode) to high(TFadingMode) do
+    if ls = UTF8LowerCase(FadingModeStr[fm]) then
+    begin
+      Result := fm;
+      break;
+    end;
+  Result := fm;
+end;
+
+procedure FadingModeStrList(s: TStrings);
+var
+  fm: TFadingMode;
+begin
+  for fm := low(TFadingMode) to high(TFadingMode) do
+    s.Add(FadingModeStr[fm]);
+end;
+
+{ TFading }
+
+procedure TFading.SetFAlpha(AValue: byte);
+begin
+  if FAlpha = AValue then
+    Exit;
+  FAlpha := AValue;
+end;
+
+procedure TFading.SetFMode(AValue: TFadingMode);
+begin
+  if FMode = AValue then
+    Exit;
+  FMode := AValue;
+  FPrevDate:= 0;
+end;
+
+procedure TFading.SetFAlphaStep(AValue: byte);
+begin
+  if FAlphaStep = AValue then
+    Exit
+  else
+    FAlphaStep := AValue;
+end;
+
+procedure TFading.SetFDuration(AValue: integer);
+begin
+  FDuration:= AValue;
+end;
+
+function TFading.Execute(AStepCount: integer= 1): byte;
+var curDate: TDateTime;
+  alphaStep: byte;
+  timeGrain: integer;
+begin
+  if FAlphaStep <= 0 then
+    alphaStep := 1
+  else
+    alphaStep := FAlphaStep;
+
+  if FDuration > 0 then
+  begin
+    curDate := Now;
+    if FPrevDate = 0 then
+    begin
+      FPrevDate := curDate;
+      FElapsedMsAccumulator := 0;
+      result := FAlpha;
+      exit;
+    end;
+
+    inc(FElapsedMsAccumulator, round((curDate-FPrevDate)*(24*60*60*1000)) );
+    timeGrain := round(FDuration*alphaStep/255);
+    if timeGrain <= 0 then timeGrain := 1;
+    AStepCount := FElapsedMsAccumulator div timeGrain;
+    FElapsedMsAccumulator:= FElapsedMsAccumulator mod timeGrain;
+    FPrevDate := curDate;
+  end;
+
+  if AStepCount < 0 then AStepCount := 0
+  else if AStepCount > 255 then AStepCount := 255;
+
+  case FMode of
+    fmFadeIn, fmFadeInOut, fmFadeInCycle:
+    begin
+      if (FAlpha = 255) and (FMode = fmFadeInCycle) then
+        FAlpha := 0
+      else
+      if FAlpha + alphaStep*AStepCount >= 255 then
+      begin
+        FAlpha := 255;
+        if FMode = fmFadeInOut then
+          FMode := fmFadeOutIn
+        else if FMode <> fmFadeInCycle then
+          FMode := fmSuspended;
+      end
+      else
+        FAlpha += alphaStep*AStepCount;
+    end;
+    fmFadeOut,fmFadeOutIn, fmFadeOutCycle:
+    begin
+      if (FAlpha = 0) and (FMode = fmFadeOutCycle) then
+        FAlpha := 255
+      else
+      if FAlpha - alphaStep*AStepCount <= 0 then
+      begin
+        FAlpha := 0;
+        if FMode = fmFadeOutIn then
+          FMode := fmFadeInOut
+        else if FMode <> fmFadeOutCycle then
+          FMode := fmSuspended;
+      end
+      else
+        FAlpha -= alphaStep*AStepCount;
+    end;
+  end;
+
+  Result := FAlpha;
+end;
+
+function TFading.Reset: byte;
+begin
+  case FMode of
+    fmFadeIn, fmFadeInOut:
+    begin
+      FAlpha := 0;
+    end;
+    fmFadeOut,fmFadeOutIn:
+    begin
+      FAlpha := 255;
+    end;
+  end;
+  Result := FAlpha;
+  FPrevDate := 0;
+end;
+
+procedure TFading.PutImage(ADestination: TBGRACustomBitmap; AX, AY: integer;
+  ASource: TBGRACustomBitmap);
+begin
+  ADestination.PutImage(AX,AY,ASource,dmDrawWithTransparency,Alpha);
+end;
+
+procedure TFading.FillRect(ADestination: TBGRACustomBitmap; ARect: TRect;
+  AColor: TBGRAPixel);
+begin
+  ADestination.FillRect(ARect, BGRA(AColor.red,AColor.green,AColor.blue,AColor.alpha*Alpha div 255),dmDrawWithTransparency);
+end;
+
+{-- Fading --}
+
+end.

+ 776 - 0
bcfilters.pas

@@ -0,0 +1,776 @@
+{
+// all pixels //
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels-1 downto 0 do
+  begin
+    p^.red := ;
+    p^.green := ;
+    p^.blue := ;
+    p^.alpha := ;
+    Inc(p);
+  end;
+
+// scan line //
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      p^.red := ;
+      p^.green := ;
+      p^.blue := ;
+      p^.alpha := ;
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+}
+
+unit bcfilters;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, StrUtils, LCLProc, Math, BGRABitmap, BGRABitmapTypes;
+
+type
+  TBCSimpleFilter = (bcsNone, bcsInvert, bcsGrayScale, bcsGrayScaleA,
+    bcsGrayScaleBGRA, bcsNoise,
+    bcsNoiseA, bcsNoiseBW, bcsNoiseBWA, bcsTVScanLinesH, bcsTVScanLinesV,
+    bcsCheckeredL, bcsCheckeredR, bcsBlackAndWhite, bcsInstagram1,
+    bcsInstagram2, bcsInstagram3, bcsInstagram4, bcsInstagram5, bcsInstagram6,
+    bcsPhotoNoise, bcsPolaroid, bcsMovement);
+
+const
+  BCSimpleFilterStr: array [TBCSimpleFilter] of string =
+    ('None', 'Invert', 'GrayScale', 'GrayScaleA', 'GrayScaleBGRA',
+    'Noise', 'NoiseA', 'NoiseBW', 'NoiseBWA', 'TVScanLinesH', 'TVScanLinesV',
+    'CheckeredL', 'CheckeredR', 'BlackAndWhite', 'Instagram1', 'Instagram2',
+    'Instagram3', 'Instagram4', 'Instagram5', 'Instagram6', 'PhotoNoise',
+    'Polaroid', 'Movement');
+
+function StrToTBCSimpleFilter(const s: ansistring): TBCSimpleFilter;
+procedure BCSimpleFilterStrList(s: TStrings);
+
+{ Invert colors, keep alpha }
+procedure Invert(Bitmap: TBGRABitmap);
+{ Invert colors, advanced options }
+procedure Invert(Bitmap: TBGRABitmap; touchR, touchG, touchB, touchA: boolean);
+
+{ GrayScale, keep alpha }
+procedure GrayScale(Bitmap: TBGRABitmap);
+{ GrayScale, keep alpha, pallete }
+procedure GrayScale(Bitmap: TBGRABitmap; pallete: byte);
+{ GrayScale, alpha 255}
+procedure GrayScaleA(Bitmap: TBGRABitmap);
+{ GrayScale, using BGRAToGrayScale }
+procedure GrayScaleBGRA(Bitmap: TBGRABitmap);
+
+{ Noise random color, keep alpha }
+procedure Noise(Bitmap: TBGRABitmap);
+{ Noise random color, advanced options }
+procedure Noise(Bitmap: TBGRABitmap; touchR, touchG, touchB, touchA: boolean);
+{ Noise random color, random alpha }
+procedure NoiseA(Bitmap: TBGRABitmap);
+
+{ Noise random color, set max posible values }
+procedure NoiseMax(Bitmap: TBGRABitmap; maxR, maxG, maxB, maxA: byte);
+{ Noise random color, set max posible values, advanced options }
+procedure NoiseMax(Bitmap: TBGRABitmap; maxR, maxG, maxB, maxA: byte;
+  touchR, touchG, touchB, touchA: boolean);
+
+{ Noise black and white, keep alpha }
+procedure NoiseBW(Bitmap: TBGRABitmap);
+{ Noise black and white, random alpha }
+procedure NoiseBWA(Bitmap: TBGRABitmap);
+
+{ TV Lines Horizontal }
+procedure TVScanLinesH(Bitmap: TBGRABitmap);
+{ TV Lines Vertical }
+procedure TVScanLinesV(Bitmap: TBGRABitmap);
+{ Checkered Left aligned }
+procedure CheckeredL(Bitmap: TBGRABitmap);
+{ Checkered Right aligned }
+procedure CheckeredR(Bitmap: TBGRABitmap);
+
+{ Black and White, middle 128 }
+procedure BlackAndWhite(Bitmap: TBGRABitmap);
+{ Black and White, custom middle }
+procedure BlackAndWhite(Bitmap: TBGRABitmap; middle: byte);
+
+{ Instagram Filters }
+// sepia
+procedure Instagram1(Bitmap: TBGRABitmap);
+// blue-green
+procedure Instagram2(Bitmap: TBGRABitmap);
+// purple
+procedure Instagram3(Bitmap: TBGRABitmap);
+// blue 3 channels
+procedure Instagram4(Bitmap: TBGRABitmap);
+// green 3 channels
+procedure Instagram5(Bitmap: TBGRABitmap);
+// red 3 channels
+procedure Instagram6(Bitmap: TBGRABitmap);
+// white rounded border
+procedure Polaroid(Bitmap: TBGRABitmap);
+// blured bw noise
+procedure PhotoNoise(Bitmap: TBGRABitmap);
+
+{ Pixel movement }
+procedure Movement(Bitmap: TBGRABitmap; randXmin: NativeInt = -5;
+  randXmax: NativeInt = 5; randYmin: NativeInt = -5; randYmax: NativeInt = 5);
+
+procedure Zoomy(Bitmap: TBGRABitmap; xMy,yMy: extended);
+
+{ Filters that only need Bitmap as parameter }
+procedure SimpleFilter(Bitmap: TBGRABitmap; Filter: TBCSimpleFilter);
+
+implementation
+
+function StrToTBCSimpleFilter(const s: ansistring): TBCSimpleFilter;
+var
+  sf: TBCSimpleFilter;
+  ls: ansistring;
+begin
+  Result := sf;
+  ls := UTF8LowerCase(s);
+  for sf := low(TBCSimpleFilter) to high(TBCSimpleFilter) do
+    if ls = UTF8LowerCase(BCSimpleFilterStr[sf]) then
+    begin
+      Result := sf;
+      break;
+    end;
+end;
+
+procedure BCSimpleFilterStrList(s: TStrings);
+var
+  sf: TBCSimpleFilter;
+begin
+  for sf := low(TBCSimpleFilter) to high(TBCSimpleFilter) do
+    s.Add(BCSimpleFilterStr[sf]);
+end;
+
+procedure Invert(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := not p^.red;
+    p^.green := not p^.green;
+    p^.blue := not p^.blue;
+    //p^.alpha := not p^.alpha;
+    Inc(p);
+  end;
+end;
+
+procedure Invert(Bitmap: TBGRABitmap; touchR, touchG, touchB, touchA: boolean);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    if touchR then
+      p^.red := not p^.red;
+    if touchG then
+      p^.green := not p^.green;
+    if touchB then
+      p^.blue := not p^.blue;
+    if touchA then
+      p^.alpha := not p^.alpha;
+    Inc(p);
+  end;
+end;
+
+procedure GrayScale(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := (p^.red + p^.green + p^.blue) div 3;
+    p^.red := c;
+    p^.green := c;
+    p^.blue := c;
+    //p^.alpha := 255;
+    Inc(p);
+  end;
+end;
+
+procedure GrayScale(Bitmap: TBGRABitmap; pallete: byte);
+var
+  i, j: integer;
+  p: PBGRAPixel;
+  c: byte;
+  gpallete: array of byte;
+begin
+  if pallete = 0 then
+    pallete := 1
+  else if pallete = 255 then
+  begin
+    GrayScale(Bitmap);
+    exit;
+  end;
+
+  SetLength(gpallete, pallete);
+
+  for i := 0 to High(gpallete) do
+  begin
+    gpallete[i] := (255 * i) div 255;
+  end;
+
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := (p^.red + p^.green + p^.blue) div 3;
+
+    for j := 0 to High(gpallete) do
+    begin
+      if (c >= gpallete[j]) and (c <= gpallete[j + 1]) then
+      begin
+        c := gpallete[j];
+        break;
+      end;
+    end;
+
+    p^.red := c;
+    p^.green := c;
+    p^.blue := c;
+    //p^.alpha := 255;
+    Inc(p);
+  end;
+end;
+
+procedure GrayScaleA(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := (p^.red + p^.green + p^.blue) div 3;
+    p^.red := c;
+    p^.green := c;
+    p^.blue := c;
+    p^.alpha := 255;
+    Inc(p);
+  end;
+end;
+
+procedure GrayScaleBGRA(Bitmap: TBGRABitmap);
+begin
+  Bitmap.InplaceGrayscale;
+{var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^ := BGRAToGrayscale(p^);
+    Inc(p);
+  end;}
+end;
+
+procedure Noise(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := Random(256);
+    p^.green := Random(256);
+    p^.blue := Random(256);
+    //p^.alpha := Random(256);
+    Inc(p);
+  end;
+end;
+
+procedure Noise(Bitmap: TBGRABitmap; touchR, touchG, touchB, touchA: boolean);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    if touchR then
+      p^.red := Random(256);
+    if touchG then
+      p^.green := Random(256);
+    if touchB then
+      p^.blue := Random(256);
+    if touchA then
+      p^.alpha := Random(256);
+    Inc(p);
+  end;
+end;
+
+procedure NoiseA(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := Random(256);
+    p^.green := Random(256);
+    p^.blue := Random(256);
+    p^.alpha := Random(256);
+    Inc(p);
+  end;
+end;
+
+procedure NoiseBW(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := Random(2);
+    p^.red := c + 255;
+    p^.green := c + 255;
+    p^.blue := c + 255;
+    //p^.alpha := Random(256);
+    Inc(p);
+  end;
+end;
+
+procedure NoiseBWA(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := Random(2);
+    p^.red := c + 255;
+    p^.green := c + 255;
+    p^.blue := c + 255;
+    p^.alpha := Random(256);
+    Inc(p);
+  end;
+end;
+
+procedure TVScanLinesH(Bitmap: TBGRABitmap);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      if Odd(y) then
+      begin
+        p^.red := 0;
+        p^.green := 0;
+        p^.blue := 0;
+        //p^.alpha := 255;
+      end;
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure TVScanLinesV(Bitmap: TBGRABitmap);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      if Odd(x) then
+      begin
+        p^.red := 0;
+        p^.green := 0;
+        p^.blue := 0;
+        //p^.alpha := 255;
+      end;
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure CheckeredL(Bitmap: TBGRABitmap);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      if Odd(y) and Odd(x) or not Odd(y) and not Odd(x) then
+      begin
+        p^.red := 0;
+        p^.green := 0;
+        p^.blue := 0;
+        p^.alpha := 255;
+      end;
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure CheckeredR(Bitmap: TBGRABitmap);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      if not Odd(y) and Odd(x) or Odd(y) and not Odd(x) then
+      begin
+        p^.red := 0;
+        p^.green := 0;
+        p^.blue := 0;
+        p^.alpha := 255;
+      end;
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure BlackAndWhite(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := (p^.red + p^.green + p^.blue) div 3;
+    if c >= 128 then
+      c := 255
+    else
+      c := 0;
+    p^.red := c;
+    p^.green := c;
+    p^.blue := c;
+    if p^.alpha > 0 then
+      p^.alpha := 255;
+    Inc(p);
+  end;
+end;
+
+procedure BlackAndWhite(Bitmap: TBGRABitmap; middle: byte);
+var
+  i: integer;
+  p: PBGRAPixel;
+  c: byte;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    c := (p^.red + p^.green + p^.blue) div 3;
+    if c >= middle then
+      c := 255
+    else
+      c := 0;
+    p^.red := c;
+    p^.green := c;
+    p^.blue := c;
+    if p^.alpha > 0 then
+      p^.alpha := 255;
+    Inc(p);
+  end;
+end;
+
+procedure Movement(Bitmap: TBGRABitmap; randXmin: NativeInt = -5;
+  randXmax: NativeInt = 5; randYmin: NativeInt = -5; randYmax: NativeInt = 5);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      p^ := Bitmap.GetPixel(x + RandomRange(randXmin, randXmax), y + RandomRange(
+        randYmin, randYmax));
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure Zoomy(Bitmap: TBGRABitmap; xMy,yMy: extended);
+var
+  x, y: integer;
+  p: PBGRAPixel;
+begin
+  for y := 0 to Bitmap.Height - 1 do
+  begin
+    p := Bitmap.Scanline[y];
+    for x := 0 to Bitmap.Width - 1 do
+    begin
+      p^{.red} := Bitmap.GetPixel(x*xMy,y*yMy);
+      {p^.green := 0;
+      p^.blue := 0;
+      p^.alpha := 255;}
+      Inc(p);
+    end;
+  end;
+  Bitmap.InvalidateBitmap;
+end;
+
+procedure SimpleFilter(Bitmap: TBGRABitmap; Filter: TBCSimpleFilter);
+begin
+  case Filter of
+    bcsInvert: Invert(Bitmap);
+    bcsGrayScale: GrayScale(Bitmap);
+    bcsGrayScaleA: GrayScaleA(Bitmap);
+    bcsGrayScaleBGRA: GrayScaleBGRA(Bitmap);
+    bcsNoise: Noise(Bitmap);
+    bcsNoiseA: NoiseA(Bitmap);
+    bcsNoiseBW: NoiseBW(Bitmap);
+    bcsNoiseBWA: NoiseBWA(Bitmap);
+    bcsTVScanLinesH: TVScanLinesH(Bitmap);
+    bcsTVScanLinesV: TVScanLinesV(Bitmap);
+    bcsCheckeredL: CheckeredL(Bitmap);
+    bcsCheckeredR: CheckeredR(Bitmap);
+    bcsBlackAndWhite: BlackAndWhite(Bitmap);
+    bcsInstagram1: Instagram1(Bitmap);
+    bcsInstagram2: Instagram2(Bitmap);
+    bcsInstagram3: Instagram3(Bitmap);
+    bcsInstagram4: Instagram4(Bitmap);
+    bcsInstagram5: Instagram5(Bitmap);
+    bcsInstagram6: Instagram6(Bitmap);
+    bcsPhotoNoise: PhotoNoise(Bitmap);
+    bcsPolaroid: Polaroid(Bitmap);
+    bcsMovement: Movement(Bitmap);
+  end;
+end;
+
+procedure NoiseMax(Bitmap: TBGRABitmap; maxR, maxG, maxB, maxA: byte);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := Random(maxR + 1);
+    p^.green := Random(maxG + 1);
+    p^.blue := Random(maxB + 1);
+    p^.alpha := Random(maxA + 1);
+    Inc(p);
+  end;
+end;
+
+procedure NoiseMax(Bitmap: TBGRABitmap; maxR, maxG, maxB, maxA: byte;
+  touchR, touchG, touchB, touchA: boolean);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    if touchR then
+      p^.red := Random(maxR + 1);
+    if touchG then
+      p^.green := Random(maxG + 1);
+    if touchB then
+      p^.blue := Random(maxB + 1);
+    if touchA then
+      p^.alpha := Random(maxA + 1);
+    Inc(p);
+  end;
+end;
+
+// 1
+procedure Instagram1(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := round(p^.red * 0.75);
+    p^.green := round(p^.red * 0.50);
+    p^.blue := round(p^.red * 0.25);
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+// 2
+procedure Instagram2(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := round(p^.red * 0.75);
+    p^.green := round(p^.green * 0.50);
+    p^.blue := round(p^.blue * 0.25);
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+// 3
+procedure Instagram3(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := p^.red;
+    p^.green := round(p^.green * 0.50);
+    p^.blue := round(p^.blue * 0.50);
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+// 4
+procedure Instagram4(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := p^.blue;
+    p^.green := p^.blue;
+    p^.blue := p^.blue;
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+// 5
+procedure Instagram5(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := p^.green;
+    p^.green := p^.green;
+    p^.blue := p^.green;
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+// 6
+procedure Instagram6(Bitmap: TBGRABitmap);
+var
+  i: integer;
+  p: PBGRAPixel;
+begin
+  p := Bitmap.Data;
+
+  for i := Bitmap.NBPixels - 1 downto 0 do
+  begin
+    p^.red := p^.red;
+    p^.green := p^.red;
+    p^.blue := p^.red;
+    //p^.alpha := ;
+    Inc(p);
+  end;
+end;
+
+procedure Polaroid(Bitmap: TBGRABitmap);
+var
+  tmp: TBGRABitmap;
+begin
+  tmp := TBGRABitmap.Create(Bitmap.Width, Bitmap.Height, BGRAWhite);
+  tmp.EraseRoundRectAntialias(
+    Round(Bitmap.Width * 0.05),
+    Round(Bitmap.Height * 0.05),
+    Bitmap.Width - Round(Bitmap.Width * 0.05),
+    Bitmap.Height - Round(Bitmap.Height * 0.05),
+    Round(Bitmap.Width * 0.05),
+    Round(Bitmap.Height * 0.05),
+    255, []);
+  Bitmap.BlendImage(0, 0, tmp, boLinearBlend);
+  tmp.Free;
+end;
+
+procedure PhotoNoise(Bitmap: TBGRABitmap);
+var
+  tmp: TBGRABitmap;
+begin
+  tmp := TBGRABitmap.Create(Bitmap.Width, Bitmap.Height);
+  NoiseBWA(tmp);
+  BGRAReplace(tmp, tmp.FilterBlurRadial(1, rbFast));
+  Bitmap.BlendImageOver(0, 0, tmp, boLinearBlend, 25);
+  tmp.Free;
+end;
+
+end.

+ 239 - 0
bcgamegrid.pas

@@ -0,0 +1,239 @@
+unit BCGameGrid;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
+  BCBaseCtrls, BGRABitmap, BGRABitmapTypes, LCLProc;
+
+type
+
+  TOnRenderControl = procedure(Sender: TObject; Bitmap: TBGRABitmap;
+    r: TRect; n, x, y: integer) of object;
+  TOnClickControl = procedure(Sender: TObject; n, x, y: integer) of object;
+
+  { TBCCustomGrid }
+
+  TBCCustomGrid = class(TBCGraphicControl)
+  private
+    FBGRA: TBGRABitmap;
+    FGridWidth: integer;
+    FGridHeight: integer;
+    FBlockWidth: integer;
+    FBlockHeight: integer;
+    FOnRenderControl: TOnRenderControl;
+    FOnClickControl: TOnClickControl;
+  private
+    procedure SetFBlockHeight(AValue: integer);
+    procedure SetFBlockWidth(AValue: integer);
+    procedure SetFGridHeight(AValue: integer);
+    procedure SetFGridWidth(AValue: integer);
+    { Private declarations }
+  protected
+    { Protected declarations }
+    procedure Click; override;
+    procedure DrawControl; override;
+    procedure RenderControl; override;
+  public
+    { Public declarations }
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure RenderAndDrawControl;
+    property GridWidth: integer read FGridWidth write SetFGridWidth;
+    property GridHeight: integer read FGridHeight write SetFGridHeight;
+    property BlockWidth: integer read FBlockWidth write SetFBlockWidth;
+    property BlockHeight: integer read FBlockHeight write SetFBlockHeight;
+    property OnRenderControl: TOnRenderControl
+      read FOnRenderControl write FOnRenderControl;
+    property OnClickControl: TOnClickControl read FOnClickControl write FOnClickControl;
+  published
+    { Published declarations }
+  end;
+
+  TBCGameGrid = class(TBCCustomGrid)
+  published
+    property GridWidth;
+    property GridHeight;
+    property BlockWidth;
+    property BlockHeight;
+    // Support 'n, x, y'
+    property OnRenderControl;
+    property OnClickControl;
+    // 'Classic' events, to be changed...
+    property OnMouseDown;
+    property OnMouseMove;
+    property OnMouseUp;
+    // Ok...
+    property OnMouseEnter;
+    property OnMouseLeave;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  {$I bcgamegrid_icon.lrs}
+  RegisterComponents('BGRA Controls', [TBCGameGrid]);
+end;
+
+{ TBCCustomGrid }
+
+procedure TBCCustomGrid.SetFBlockHeight(AValue: integer);
+begin
+  if FBlockHeight = AValue then
+    Exit;
+  if AValue < 1 then
+    FBlockHeight := 1
+  else
+    FBlockHeight := AValue;
+
+  RenderAndDrawControl;
+end;
+
+procedure TBCCustomGrid.SetFBlockWidth(AValue: integer);
+begin
+  if FBlockWidth = AValue then
+    Exit;
+  if AValue < 1 then
+    FBlockWidth := 1
+  else
+    FBlockWidth := AValue;
+
+  RenderAndDrawControl;
+end;
+
+procedure TBCCustomGrid.SetFGridHeight(AValue: integer);
+begin
+  if FGridHeight = AValue then
+    Exit;
+  if AValue < 1 then
+    FGridHeight := 1
+  else
+    FGridHeight := AValue;
+
+  RenderAndDrawControl;
+end;
+
+procedure TBCCustomGrid.SetFGridWidth(AValue: integer);
+begin
+  if FGridWidth = AValue then
+    Exit;
+  if AValue < 1 then
+    FGridWidth := 1
+  else
+    FGridWidth := AValue;
+
+  RenderAndDrawControl;
+end;
+
+procedure TBCCustomGrid.Click;
+var
+  n, x, y: integer;
+  r: TRect;
+var
+  pos: TPoint;
+begin
+  if (BlockWidth <= 0) or (BlockHeight <= 0) or (GridWidth <= 0) or
+    (GridHeight <= 0) then
+    Exit;
+
+  pos := ScreenToClient(Mouse.CursorPos);
+
+  n := 0;
+
+  for y := 0 to GridHeight - 1 do
+  begin
+    for x := 0 to GridWidth - 1 do
+    begin
+      r.Left := BlockWidth * x;
+      r.Top := BlockHeight * y;
+      r.Right := r.Left + BlockWidth;
+      r.Bottom := r.Top + BlockHeight;
+
+      if (pos.x >= r.Left) and (pos.x <= r.Right) and (pos.y >= r.Top) and
+        (pos.y <= r.Bottom) then
+      begin
+        //DebugLn(['TControl.Click ',DbgSName(Self)]);
+        if Assigned(FOnClickControl) and (Action <> nil) and
+          (not CompareMethods(TMethod(Action.OnExecute), TMethod(FOnClickControl))) then
+          // the OnClick is set and differs from the Action => call the OnClick
+          FOnClickControl(Self, n, x, y)
+        else if (not (csDesigning in ComponentState)) and (ActionLink <> nil) then
+          ActionLink.Execute(Self)
+        else if Assigned(FOnClickControl) then
+          FOnClickControl(Self, n, x, y);
+      end;
+
+      Inc(n);
+    end;
+  end;
+end;
+
+procedure TBCCustomGrid.DrawControl;
+begin
+  if FBGRA <> nil then
+    FBGRA.Draw(Canvas, 0, 0, False);
+end;
+
+procedure TBCCustomGrid.RenderControl;
+var
+  n, x, y: integer;
+  r: TRect;
+begin
+  if (BlockWidth <= 0) or (BlockHeight <= 0) or (GridWidth <= 0) or
+    (GridHeight <= 0) then
+    Exit;
+
+  if FBGRA <> nil then
+    FreeAndNil(FBGRA);
+
+  FBGRA := TBGRABitmap.Create(Width, Height);
+
+  n := 0;
+
+  for y := 0 to GridHeight - 1 do
+  begin
+    for x := 0 to GridWidth - 1 do
+    begin
+      r.Left := BlockWidth * x;
+      r.Top := BlockHeight * y;
+      r.Right := r.Left + BlockWidth;
+      r.Bottom := r.Top + BlockHeight;
+
+      FBGRA.Rectangle(r, BGRA(127, 127, 127, 127), BGRA(255, 255, 255, 127),
+        dmDrawWithTransparency);
+
+      if Assigned(FOnRenderControl) then
+        FOnRenderControl(Self, FBGRA, r, n, x, y);
+
+      Inc(n);
+    end;
+  end;
+end;
+
+procedure TBCCustomGrid.RenderAndDrawControl;
+begin
+  RenderControl;
+  Invalidate;
+end;
+
+constructor TBCCustomGrid.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+end;
+
+destructor TBCCustomGrid.Destroy;
+begin
+  if FBGRA <> nil then
+    FreeAndNil(FBGRA);
+  inherited Destroy;
+end;
+
+end.

+ 63 - 0
bcgamegrid_icon.lrs

@@ -0,0 +1,63 @@
+LazarusResources.Add('TBCGameGrid','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#5'nIDATx'#218#133#149'kLSg'#24#199#207#233'9'#244#244#6#135#182#20'z'#129
+  +#210'r'#137#10#148#137'Np'#19'/'#219#216#230#188#196'%'#243#155#151'mq'#153
+  +#238#155#153's'#223#212'D'#220#135#197#153'%'#243#195't'#209#205'-N'#151'E'
+  +#150',C'#151'EM&C''j'#4'Z0'#11#21#6#5#214'ri'#161#210'r'#232'}'#255#183'-p'
+  +#172'ekr8'#237'9'#127#158#231'}'#159#247#247#127#30#154#194#199'Z'#245#188
+  +#133#147'+K'#159'L'#141';'#212#5'F'#155'wl'#216#174')*'#174#13#250'}.6'#135
+  +#227#19#137#4#21#141#132#252#170'|'#173#217'76'#234#208#20#154'lS'#19#255#216
+  +'ymQm'#192#239'u'#201#149'y<M'#211'T$4'#231'W'#242#26#243#244#164#219#161#214
+  +#25'm'#1#191#207'N'#235#140'V'#137'e'#197#170'fN'#166'X'#209#213'~'#245'x'
+  +#133'm'#237';N'#199#221#11#149#184#187']'#206'[u'#141'['#14'=v'#220#253#9#226
+  +#1#189#185'r'#19#190'_'#152#215#212'5n=:'#227#247':'#131'~'#175#7#235'L@3'
+  +#152#214'|'#219#184'u'#207#153#190#238'?'#143#209'Z'#189#153#13#9#129#213#225
+  +'9A'#8#135#132'!'#8#165#184#194#233';'#173'),^'#227#27#31#233#196'w'#1#23'+z'
+  +#23#150'r'#242'R'#169'L'#174'B`''~'#199#211#23#209#196'T'#188#166#26'1'#221
+  +'t'#190#206#200'X'#150#173'<'#142#213#182#143#185#156#191'R'#162#143'2O-]'
+  +#191'm'#239#141#155'-g_'#199#246#5'*'#227#131#213#190'Qd'#174'l'#28'~'#220's'
+  +#212#231'q'#197#230#159#235#140#22#198'TV'#149#140'I'#171'u&'#150#147'+'#182
+  +'a'#171#131#168'y'#215#211#9'42Ci'#229#129#161#190#238'sH'#16#200'L'#128'U'
+  +#174'T'#242'ZK4'#28'j'#245'z\'#209#197#4'V'#150'a'#217'd'#204#228#14#10#244
+  +'%'#251#189'c#'#221'S'#227#163#183'3'#18'H'#171#235'_:'#221#217'v'#245'`$'
+  +#252#236#14'P'#190'u'#234'"'#211'sS'#19#238#179#226#29#20#24'J'#153#252#2'}2'
+  +'&'#205#23#24'X'#157#193'|'#0'?'#236'H'#208'&'#14#160#200'U'#203'j'#26'^'#254
+  +#226'a['#235#135'Xe K'#130#13'HP'#139#255';'#227#27#27#137#138#18#176'H'#144
+  +#140'I'#231'i'#10#25#185#138#223#134'z'#174#243#12#245'}U^S'#191#203'i'#191
+  +'{'#177#194#214#176'{'#248#177#163#3#248'.'#151'H'#24'!'#26#9';'#161'Y'#223
+  +#239#232#248#190#220#214#176#171#191#231#222'E'#131'e'#217'~'#143#203'yGg('
+  +#213#162'$'#177#128#127#202'E4}]'#237#151#141'eU'#239#131#166#239#176#3'=c]'
+  +#190#234#4'*'#16#199#131'o'#192#255#26#172#230'>'#185#131#241'A'#224#246#217
+  +#189#27'-'#159#132'C'#179#147'*^[>'#255#142#220'+j'#215#190#155#195#201#185
+  +#225'>'#251'MB'#16'4Si'#205#131#250#166#157#159#2#229#243'4'#196'Lhn'#150'`:'
+  +#3#175#12#194'S'#12#193#12#23#19#139'FX'#152#233#197#233#9'wG'#142#148#19#18
+  +#20'%'#153#127#7'm'#140'JP'#150#28#153#156#15#11#193'G'#180#132'!'#207'!'#161
+  +'$'#137'x'#156#146#202#21#181#136#233#153#199#180'9'#141#233#181#12'L9`z'#29
+  +#152'n'#6'E'#179'Y0'#221'B0'#29#233#239'9'#226'u'#139#14#25#152#22#151'U%c'
+  +#146#4'l4<W'#135'l>'#24#173'?#'#129#140#147')7'#206'LO'#222#6'E'#207#28'2'
+  +#140'V'#14#163'i8'#185#170#243'iL-'#172#16'|'#146#140'I'#243'Z'#3'c]Q'#151
+  +#221'h'#185'0'#218'v'#24#237#10#140#22#254#15#163'9'#237'GQ'#247#133#29'h'
+  +#129'iIyu'#202'h'#188'V'#207#202#149#185'Y'#141#166#200#205#151#25'-'#203#14
+  +#12#254#213'u'#14#205'nI'#163'E'#230'f[}'#227#163#11'; '#237#7'g'#150'2'#26
+  +#193#180#208'd'#205'j4tI'#169#237#133'WO?'#188#245#203'A`'#186#164#209'P'#255
+  +#179#232#160#177#197#231'&'#6#240#164#140#134#182#202'j'#245'%'#31#160'C'#238
+  +#6#142#135#234#155#222':'#217'q'#227#202#225#134#166#157''''#129#217#15'Z'
+  +#180'mB'#14'J'#208#5#205#30'h'#14#139'4'#167#160#185#12'M5'#193#20#154'n'#145
+  +#230#20'4'#31#211'jd'#147#202#20';'#192#252'8J'#244#8'B'#14'W(}O'#192'T{'#137
+  +#185#168'T'#23'eE'#239'B(Q'#21'Jd'#196#217#181#165#17#157#239#166#17#156#205
+  +'k'#136#217'KZ'#5#140'Vw'#2#7'r''2''\'#139''''#226'4'#17#227#15#13#18#164#155
+  +#222#220#247#219#245#31#191#220#154#171'.'#8#226'9'#240#167'a'#149#4#230#11
+  +#157#192#12'!'#152#174#27#232#189#127#12'5'#143#146#183'HC'#163#156#146#178
+  +#170#213#228#144#255' '#135#204'D'#163'a'#130#148'7'#18#18#254#206'8d'#14#173
+  +'bc`'#218'K0'#13'f'#193#212#10#163'i9N'#209#137#153#177'x'#6'E%0o0'#25'3'#153
+  +#192#138#137#150#205'h$'#193#134#237'o_'#7#166#155#145'`I'#163#161'U'#28#17
+  +''''#0'ELIEM'#243#2#166#177#212#14#158'1'#26#193#20#3#235#127#141#134'{g&'
+  +#166#152#146')'#163#161'91'#232#156#199'1'#176#166'''F'#7#206#147'a'#157#26
+  +#250'%'#181'p'#167#27#164#156'{'#240#251#207#31#177'l'#206#4#180'f'#172#20'C'
+  +#191#24'C'#127#212'^T\'#241#30'J'#164#246#186#135'Z'#152#28'i'#12'%'#246#227
+  +#224#205#19#163#131#189#213#245#175'|'#14#194'.'#17#31#176#10#21#191'#='#172
+  +#207'g'#12#253#246'\^S'#134'EE'#179#13'}h'#246#165'5&B'#144'x'#232'C'#179#15
+  +#154#175'1'#212'M'#146#224#204't^H'#8'J'#211#8#138#135'~'#178's'#166#17#140
+  +'Q'#25'C?'#141'kLT'#181#184'H#'#203#211#232#130#255#2'BE1<'#194#178'[O'#0#0#0
+  +#0'IEND'#174'B`'#130
+]);

+ 1008 - 0
bcimagebutton.pas

@@ -0,0 +1,1008 @@
+unit BCImageButton;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, LResources, LMessages, ExtCtrls,
+  { BGRAControls }
+  BCBaseCtrls, BCEffect,
+  { BGRABitmap }
+  BGRABitmap, BGRABitmapTypes, BGRASliceScaling;
+
+{off $DEFINE DEBUG}
+
+function CalculateAspectRatioH(W1, H1, W2: integer): integer; //result H2
+function CalculateAspectRatioW(W1, H1, H2: integer): integer; //result W2
+function CalculateDestRect(ImageW, ImageH, DestW, DestH: integer;
+  Stretch, Proportional, Center: boolean): TRect;
+procedure AssignFontToBGRA(Source: TFont; Dest: TBGRABitmap);
+
+type
+  TBCGraphicButtonState = (gbsNormal, gbsHover, gbsActive, gbsDisabled);
+
+  TOnRenderControl = procedure(Sender: TObject; Bitmap: TBGRABitmap;
+    State: TBCGraphicButtonState) of object;
+
+type
+
+  { TBCGraphicButton }
+
+  TBCGraphicButton = class(TBCGraphicControl)
+  protected
+    FState: TBCGraphicButtonState;
+    FModalResult: TModalResult;
+  protected
+    procedure DoClick; virtual;
+    procedure DoMouseDown; virtual;
+    procedure DoMouseUp; virtual;
+    procedure DoMouseEnter; virtual;
+    procedure DoMouseLeave; virtual;
+  protected
+    procedure Click; override;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
+      X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseEnter; override;
+    procedure MouseLeave; override;
+  public
+    property ModalResult: TModalResult
+      read FModalResult write FModalResult default mrNone;
+  end;
+
+  { TBCXButton }
+  TBCXButton = class(TBCGraphicButton)
+  private
+    FOnRenderControl: TOnRenderControl;
+    FBGRANormal, FBGRAHover, FBGRAActive, FBGRADisabled: TBGRABitmap;
+  protected
+    procedure DrawControl; override;
+    procedure RenderControl; override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+  published
+    property OnRenderControl: TOnRenderControl
+      read FOnRenderControl write FOnRenderControl;
+  end;
+
+  { TBCSliceScalingOptions }
+
+  TBCCustomSliceScalingOptions = class(TPersistent)
+  protected
+    FOwner: TControl;
+    FBitmap: TBGRABitmap;
+    FAutoDetectRepeat, FRepeatTop, FRepeatLeft, FRepeatMiddleHorizontal,
+    FRepeatMiddleVertical, FRepeatRight, FRepeatBottom: boolean;
+    FMarginTop, FMarginRight, FMarginBottom, FMarginLeft, FNumberOfItems: integer;
+    FDirection: TSliceScalingDirection;
+    FDrawMode: TDrawMode;
+    FResampleMode: TResampleMode;
+    FResampleFilter: TResampleFilter;
+  private
+    procedure SetFBitmap(AValue: TBGRABitmap);
+    procedure SetFMarginBottom(AValue: integer);
+    procedure SetFMarginLeft(AValue: integer);
+    procedure SetFMarginRight(AValue: integer);
+    procedure SetFMarginTop(AValue: integer);
+    procedure SetFAutoDetectRepeat(AValue: boolean);
+    procedure SetFDirection(AValue: TSliceScalingDirection);
+    procedure SetFDrawMode(AValue: TDrawMode);
+    procedure SetFNumberOfItems(AValue: integer);
+    procedure SetFRepeatBottom(AValue: boolean);
+    procedure SetFRepeatLeft(AValue: boolean);
+    procedure SetFRepeatMiddleHorizontal(AValue: boolean);
+    procedure SetFRepeatMiddleVertical(AValue: boolean);
+    procedure SetFRepeatRight(AValue: boolean);
+    procedure SetFRepeatTop(AValue: boolean);
+    procedure SetFResampleFilter(AValue: TResampleFilter);
+    procedure SetFResampleMode(AValue: TResampleMode);
+  public
+    constructor Create(AOwner: TControl);
+    destructor Destroy; override;
+  published
+    property Bitmap: TBGRABitmap read FBitmap write SetFBitmap;
+    property AutoDetectRepeat: boolean read FAutoDetectRepeat
+      write SetFAutoDetectRepeat default False;
+    property RepeatTop: boolean read FRepeatTop write SetFRepeatTop default False;
+    property RepeatLeft: boolean read FRepeatLeft write SetFRepeatLeft default False;
+    property RepeatMiddleHorizontal: boolean
+      read FRepeatMiddleHorizontal write SetFRepeatMiddleHorizontal default False;
+    property RepeatMiddleVertical: boolean read FRepeatMiddleVertical
+      write SetFRepeatMiddleVertical default False;
+    property RepeatRight: boolean read FRepeatRight write SetFRepeatRight default False;
+    property RepeatBottom: boolean
+      read FRepeatBottom write SetFRepeatBottom default False;
+    property MarginTop: integer read FMarginTop write SetFMarginTop default 0;
+    property MarginRight: integer read FMarginRight write SetFMarginRight default 0;
+    property MarginBottom: integer read FMarginBottom write SetFMarginBottom default 0;
+    property MarginLeft: integer read FMarginLeft write SetFMarginLeft default 0;
+    property NumberOfItems: integer
+      read FNumberOfItems write SetFNumberOfItems default 1;
+    property Direction: TSliceScalingDirection read FDirection write SetFDirection;
+    property DrawMode: TDrawMode read FDrawMode write SetFDrawMode default
+      dmDrawWithTransparency;
+    property ResampleMode: TResampleMode read FResampleMode
+      write SetFResampleMode default rmFineResample;
+    property ResampleFilter: TResampleFilter read FResampleFilter
+      write SetFResampleFilter default rfBestQuality;
+  end;
+
+  { TBCImageButtonSliceScalingOptions }
+
+  TBCImageButtonSliceScalingOptions = class(TBCCustomSliceScalingOptions)
+  private
+    procedure SetFCenter(AValue: boolean);
+    procedure SetFProportional(AValue: boolean);
+    procedure SetFStretch(AValue: boolean);
+  protected
+    FCenter, FStretch, FProportional: boolean;
+  published
+    property NumberOfItems: integer read FNumberOfItems default 4;
+    property Center: boolean read FCenter write SetFCenter default True;
+    property Stretch: boolean read FStretch write SetFStretch default True;
+    property Proportional: boolean
+      read FProportional write SetFProportional default False;
+  public
+    constructor Create(AOwner: TControl);
+  end;
+
+  { TBCCustomImageButton }
+
+  TBCCustomImageButton = class(TBCGraphicButton)
+  private
+    { Private declarations }
+    {$IFDEF DEBUG}
+    FDrawCount: integer;
+    FRenderCount: integer;
+    {$ENDIF}
+    FBitmapOptions: TBCImageButtonSliceScalingOptions;
+    FBGRAMultiSliceScaling: TBGRAMultiSliceScaling;
+    FBGRANormal, FBGRAHover, FBGRAActive, FBGRADisabled: TBGRABitmap;
+    FDestRect: TRect;
+    FTimer: TTimer;
+    FFade: TFading;
+    procedure SetFBitmapOptions(AValue: TBCImageButtonSliceScalingOptions);
+    procedure Fade(Sender: TObject);
+  protected
+    { Protected declarations }
+    procedure DrawControl; override;
+    procedure RenderControl; override;
+    procedure CMChanged(var Message: TLMessage); message CM_CHANGED; virtual;
+    {$IFDEF DEBUG}
+    function GetDebugText: string;
+    {$ENDIF}
+    procedure DoMouseDown; override;
+    procedure DoMouseUp; override;
+    procedure DoMouseEnter; override;
+    procedure DoMouseLeave; override;
+  public
+    { Public declarations }
+    property BitmapOptions: TBCImageButtonSliceScalingOptions
+      read FBitmapOptions write SetFBitmapOptions;
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+  published
+    { Published declarations }
+  end;
+
+  TBCImageButton = class(TBCCustomImageButton)
+  published
+    property Action;
+    property Align;
+    property Anchors;
+    //property Animation;
+    property AutoSize;
+    //property AutoSizeExtraHorizontal;
+    //property AutoSizeExtraVertical;
+    property BidiMode;
+    //property Bitmap;
+    //property BitmapFile;
+    property BitmapOptions;
+    property BorderSpacing;
+    property Caption;
+    //property Checked;
+    property Color;
+    property Constraints;
+    property DragCursor;
+    property DragKind;
+    property DragMode;
+    property Enabled;
+    property Font;
+    property ModalResult;
+    property OnChangeBounds;
+    property OnClick;
+    property OnContextPopup;
+    property OnDragDrop;
+    property OnDragOver;
+    property OnEndDrag;
+    property OnMouseDown;
+    property OnMouseMove;
+    property OnMouseUp;
+    property OnMouseEnter;
+    property OnMouseLeave;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    //property OnPlaySound;
+    //property OnRedraw;
+    property OnResize;
+    property OnStartDrag;
+    property ParentBidiMode;
+    property ParentFont;
+    property ParentShowHint;
+    property PopupMenu;
+    //property Shadow;
+    property ShowHint;
+    //property Sound;
+    //property SoundClick;
+    //property SoundEnter;
+    //property TextVisible;
+    //property Toggle;
+    property Visible;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  {$I bcimagebutton_icon.lrs}
+  RegisterComponents('BGRA Controls', [TBCImageButton]);
+  RegisterComponents('BGRA Controls', [TBCXButton]);
+end;
+
+function CalculateAspectRatioH(W1, H1, W2: integer): integer;
+begin
+  Result := Round(H1 / W1 * W2);
+end;
+
+function CalculateAspectRatioW(W1, H1, H2: integer): integer;
+begin
+  Result := Round(W1 / H1 * H2);
+end;
+
+function CalculateDestRect(ImageW, ImageH, DestW, DestH: integer;
+  Stretch, Proportional, Center: boolean): TRect;
+var
+  w: integer;
+  h: integer;
+begin
+  // Stretch or Proportional when Image (Width or Height) is bigger than Destination
+  if Stretch or (Proportional and ((ImageW > DestW) or (ImageH > DestH))) then
+  begin
+    // Proportional when Image (Width or Height) is bigger than 0
+    if Proportional and (ImageW > 0) and (ImageH > 0) then
+    begin
+      w := DestW;
+      h := CalculateAspectRatioH(ImageW, ImageH, DestW);
+      if h > DestH then
+      begin
+        h := DestH;
+        w := CalculateAspectRatioW(ImageW, ImageH, DestH);
+      end;
+      ImageW := w;
+      ImageH := h;
+    end
+    // Stretch not Proportional or when Image (Width or Height) is 0
+    else
+    begin
+      ImageW := DestW;
+      ImageH := DestH;
+    end;
+  end;
+
+  Result := Rect(0, 0, ImageW, ImageH);
+
+  // Center: Destination (Width or Height) - Image divided by 2
+  if Center then
+  begin
+    Result.Left := Round((DestW - ImageW) div 2);
+    Result.Top := Round((DestH - ImageH) div 2);
+  end;
+end;
+
+procedure AssignFontToBGRA(Source: TFont; Dest: TBGRABitmap);
+begin
+  Dest.FontAntialias := True;
+
+  Dest.FontName := Source.Name;
+  Dest.FontStyle := Source.Style;
+  Dest.FontOrientation := Source.Orientation;
+
+  case Source.Quality of
+    fqNonAntialiased: Dest.FontQuality := fqSystem;
+    fqAntialiased: Dest.FontQuality := fqFineAntialiasing;
+    fqProof: Dest.FontQuality := fqFineClearTypeRGB;
+    fqDefault, fqDraft, fqCleartype, fqCleartypeNatural: Dest.FontQuality :=
+        fqSystemClearType;
+  end;
+
+  Dest.FontHeight := -Source.Height;
+end;
+
+{ TBCXButton }
+
+procedure TBCXButton.DrawControl;
+begin
+  if Enabled then
+    case FState of
+      gbsNormal: FBGRANormal.Draw(Canvas, 0, 0, False);
+      gbsHover: FBGRAHover.Draw(Canvas, 0, 0, False);
+      gbsActive: FBGRAActive.Draw(Canvas, 0, 0, False);
+    end
+  else
+    FBGRADisabled.Draw(Canvas, 0, 0, False);
+end;
+
+procedure TBCXButton.RenderControl;
+begin
+  { Free cache bitmaps }
+  if FBGRANormal <> nil then
+    FreeAndNil(FBGRANormal);
+  if FBGRAHover <> nil then
+    FreeAndNil(FBGRAHover);
+  if FBGRAActive <> nil then
+    FreeAndNil(FBGRAActive);
+  if FBGRADisabled <> nil then
+    FreeAndNil(FBGRADisabled);
+
+  { Create cache bitmaps }
+  FBGRANormal := TBGRABitmap.Create(Width, Height);
+  FBGRAHover := TBGRABitmap.Create(Width, Height);
+  FBGRAActive := TBGRABitmap.Create(Width, Height);
+  FBGRADisabled := TBGRABitmap.Create(Width, Height);
+
+  if Assigned(FOnRenderControl) then
+  begin
+    FOnRenderControl(Self, FBGRANormal, gbsNormal);
+    FOnRenderControl(Self, FBGRAHover, gbsHover);
+    FOnRenderControl(Self, FBGRAActive, gbsActive);
+    FOnRenderControl(Self, FBGRADisabled, gbsDisabled);
+  end;
+end;
+
+constructor TBCXButton.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+end;
+
+destructor TBCXButton.Destroy;
+begin
+  if FBGRANormal <> nil then
+    FreeAndNil(FBGRANormal);
+  if FBGRAHover <> nil then
+    FreeAndNil(FBGRAHover);
+  if FBGRAActive <> nil then
+    FreeAndNil(FBGRAActive);
+  if FBGRADisabled <> nil then
+    FreeAndNil(FBGRADisabled);
+  inherited Destroy;
+end;
+
+{ TBCImageButtonSliceScalingOptions }
+
+procedure TBCImageButtonSliceScalingOptions.SetFCenter(AValue: boolean);
+begin
+  if FCenter = AValue then
+    Exit;
+  FCenter := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCImageButtonSliceScalingOptions.SetFProportional(AValue: boolean);
+begin
+  if FProportional = AValue then
+    Exit;
+  FProportional := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCImageButtonSliceScalingOptions.SetFStretch(AValue: boolean);
+begin
+  if FStretch = AValue then
+    Exit;
+  FStretch := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+constructor TBCImageButtonSliceScalingOptions.Create(AOwner: TControl);
+begin
+  inherited Create(AOwner);
+  FNumberOfItems := 4;
+  FCenter := True;
+  FProportional := False;
+  FStretch := True;
+end;
+
+{ TBCCustomSliceScalingOptions }
+
+procedure TBCCustomSliceScalingOptions.SetFBitmap(AValue: TBGRABitmap);
+begin
+  if FBitmap = AValue then
+    Exit;
+  FBitmap := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFMarginBottom(AValue: integer);
+begin
+  if FMarginBottom = AValue then
+    Exit;
+  FMarginBottom := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFMarginLeft(AValue: integer);
+begin
+  if FMarginLeft = AValue then
+    Exit;
+  FMarginLeft := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFMarginRight(AValue: integer);
+begin
+  if FMarginRight = AValue then
+    Exit;
+  FMarginRight := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFMarginTop(AValue: integer);
+begin
+  if FMarginTop = AValue then
+    Exit;
+  FMarginTop := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFAutoDetectRepeat(AValue: boolean);
+begin
+  if FAutoDetectRepeat = AValue then
+    Exit;
+  FAutoDetectRepeat := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFDirection(AValue: TSliceScalingDirection);
+begin
+  if FDirection = AValue then
+    Exit;
+  FDirection := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFDrawMode(AValue: TDrawMode);
+begin
+  if FDrawMode = AValue then
+    Exit;
+  FDrawMode := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFNumberOfItems(AValue: integer);
+begin
+  if FNumberOfItems = AValue then
+    Exit;
+  FNumberOfItems := AValue;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatBottom(AValue: boolean);
+begin
+  if FRepeatBottom = AValue then
+    Exit;
+  FRepeatBottom := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatLeft(AValue: boolean);
+begin
+  if FRepeatLeft = AValue then
+    Exit;
+  FRepeatLeft := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatMiddleHorizontal(AValue: boolean);
+begin
+  if FRepeatMiddleHorizontal = AValue then
+    Exit;
+  FRepeatMiddleHorizontal := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatMiddleVertical(AValue: boolean);
+begin
+  if FRepeatMiddleVertical = AValue then
+    Exit;
+  FRepeatMiddleVertical := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatRight(AValue: boolean);
+begin
+  if FRepeatRight = AValue then
+    Exit;
+  FRepeatRight := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFRepeatTop(AValue: boolean);
+begin
+  if FRepeatTop = AValue then
+    Exit;
+  FRepeatTop := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFResampleFilter(AValue: TResampleFilter);
+begin
+  if FResampleFilter = AValue then
+    Exit;
+  FResampleFilter := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+procedure TBCCustomSliceScalingOptions.SetFResampleMode(AValue: TResampleMode);
+begin
+  if FResampleMode = AValue then
+    Exit;
+  FResampleMode := AValue;
+
+  FOwner.Perform(CM_CHANGED, 0, 0);
+  FOwner.Invalidate;
+end;
+
+constructor TBCCustomSliceScalingOptions.Create(AOwner: TControl);
+begin
+  FOwner := AOwner;
+  FBitmap := nil;
+  FAutoDetectRepeat := False;
+  FRepeatTop := False;
+  FRepeatLeft := False;
+  FRepeatMiddleHorizontal := False;
+  FRepeatMiddleVertical := False;
+  FRepeatRight := False;
+  FRepeatBottom := False;
+  FMarginTop := 0;
+  FMarginRight := 0;
+  FMarginBottom := 0;
+  FMarginLeft := 0;
+  FNumberOfItems := 1;
+  FDirection := sdVertical;
+  FDrawMode := dmDrawWithTransparency;
+  FResampleMode := rmFineResample;
+  FResampleFilter := rfBestQuality;
+  inherited Create;
+end;
+
+destructor TBCCustomSliceScalingOptions.Destroy;
+begin
+  if FBitmap <> nil then
+    FreeAndNil(FBitmap);
+  inherited Destroy;
+end;
+
+{ TBCGraphicButton }
+
+procedure TBCGraphicButton.DoClick;
+var
+  Form: TCustomForm;
+begin
+  if ModalResult <> mrNone then
+  begin
+    Form := GetParentForm(Self);
+    if Form <> nil then
+      Form.ModalResult := ModalResult;
+  end;
+end;
+
+procedure TBCGraphicButton.DoMouseDown;
+var
+  NewState: TBCGraphicButtonState;
+begin
+  NewState := gbsActive;
+
+  if NewState <> FState then
+  begin
+    FState := NewState;
+    Invalidate;
+  end;
+end;
+
+procedure TBCGraphicButton.DoMouseUp;
+var
+  NewState: TBCGraphicButtonState;
+  p: TPoint;
+begin
+  p := ScreenToClient(Mouse.CursorPos);
+
+  if (p.x >= 0) and (p.x <= Width) and (p.y >= 0) and (p.y <= Height) then
+    NewState := gbsHover
+  else
+    NewState := gbsNormal;
+
+  if NewState <> FState then
+  begin
+    FState := NewState;
+    Invalidate;
+  end;
+end;
+
+procedure TBCGraphicButton.DoMouseEnter;
+var
+  NewState: TBCGraphicButtonState;
+begin
+  if Enabled then
+    NewState := gbsHover
+  else
+  begin
+    FState := gbsNormal;
+    NewState := FState;
+  end;
+
+  if NewState <> FState then
+  begin
+    FState := NewState;
+    Invalidate;
+  end;
+end;
+
+procedure TBCGraphicButton.DoMouseLeave;
+var
+  NewState: TBCGraphicButtonState;
+begin
+  if Enabled then
+    NewState := gbsNormal
+  else
+  begin
+    FState := gbsNormal;
+    NewState := FState;
+  end;
+
+  if NewState <> FState then
+  begin
+    FState := NewState;
+    Invalidate;
+  end;
+end;
+
+procedure TBCGraphicButton.Click;
+begin
+  DoClick;
+  inherited Click;
+end;
+
+procedure TBCGraphicButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
+  X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if Button = mbLeft then
+    DoMouseDown;
+end;
+
+procedure TBCGraphicButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
+  X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+  DoMouseUp;
+end;
+
+procedure TBCGraphicButton.MouseEnter;
+begin
+  inherited MouseEnter;
+  DoMouseEnter;
+end;
+
+procedure TBCGraphicButton.MouseLeave;
+begin
+  inherited MouseLeave;
+  DoMouseLeave;
+end;
+
+{ TBCCustomImageButton }
+
+procedure TBCCustomImageButton.Fade(Sender: TObject);
+begin
+  if FFade.Mode <> fmSuspended then
+    Invalidate;
+end;
+
+procedure TBCCustomImageButton.SetFBitmapOptions(AValue:
+  TBCImageButtonSliceScalingOptions);
+begin
+  if FBitmapOptions = AValue then
+    Exit;
+  FBitmapOptions := AValue;
+end;
+
+procedure TBCCustomImageButton.DrawControl;
+var
+  temp: TBGRABitmap;
+begin
+  if Color <> clDefault then
+  begin
+    Canvas.Brush.Color := Color;
+    Canvas.FillRect(0, 0, Width, Height);
+  end;
+
+  if Enabled then
+  begin
+    case FState of
+      gbsNormal, gbsHover: FBGRANormal.Draw(Canvas, FDestRect.Left,
+          FDestRect.Top, False);
+      gbsActive: FBGRAActive.Draw(Canvas, FDestRect.Left, FDestRect.Top, False);
+    end;
+
+    temp := TBGRABitmap.Create(Width, Height);
+    FFade.Execute;
+    FFade.PutImage(temp, 0, 0, FBGRAHover);
+
+    temp.Draw(Canvas, FDestRect.Left, FDestRect.Top, False);
+    temp.Free;
+  end
+  else
+    FBGRADisabled.Draw(Canvas, FDestRect.Left, FDestRect.Top, False);
+
+  {$IFDEF DEBUG}
+  FDrawCount += 1;
+  {$ENDIF}
+
+  {$IFDEF DEBUG}
+  Canvas.Brush.Color := clWhite;
+  Canvas.TextOut(0, 0, GetDebugText);
+  {$ENDIF}
+end;
+
+procedure TBCCustomImageButton.RenderControl;
+
+  procedure DrawText(ABitmap: TBGRABitmap);
+  begin
+    AssignFontToBGRA(Font, ABitmap);
+    ABitmap.TextRect(Rect(0, 0, Width, Height), Caption, taCenter, tlCenter,
+      ColorToBGRA(ColorToRGB(Font.Color)));
+  end;
+
+{$IFDEF DEBUG}
+const
+  Debug = True;
+{$ELSE}
+const
+  Debug = False;
+{$ENDIF}
+var
+  i: integer;
+begin
+  { Free cache bitmaps }
+  if FBGRANormal <> nil then
+    FreeAndNil(FBGRANormal);
+  if FBGRAHover <> nil then
+    FreeAndNil(FBGRAHover);
+  if FBGRAActive <> nil then
+    FreeAndNil(FBGRAActive);
+  if FBGRADisabled <> nil then
+    FreeAndNil(FBGRADisabled);
+
+  { Create cache bitmaps }
+  FBGRANormal := TBGRABitmap.Create(Width, Height);
+  FBGRAHover := TBGRABitmap.Create(Width, Height);
+  FBGRAActive := TBGRABitmap.Create(Width, Height);
+  FBGRADisabled := TBGRABitmap.Create(Width, Height);
+
+  { Free FBGRAMultiSliceScaling }
+  if FBGRAMultiSliceScaling <> nil then
+    FreeAndNil(FBGRAMultiSliceScaling);
+
+  if (FBitmapOptions.Bitmap <> nil) then
+  begin
+    { Create FBGRAMultiSliceScaling }
+    FBGRAMultiSliceScaling := TBGRAMultiSliceScaling.Create(FBitmapOptions.Bitmap,
+      FBitmapOptions.MarginTop, FBitmapOptions.MarginRight,
+      FBitmapOptions.MarginBottom, FBitmapOptions.MarginLeft,
+      FBitmapOptions.NumberOfItems, FBitmapOptions.Direction);
+
+    { Set FBGRAMultiSliceScaling properties }
+    for i := 0 to High(FBGRAMultiSliceScaling.SliceScalingArray) do
+    begin
+      FBGRAMultiSliceScaling.SliceScalingArray[i].ResampleFilter :=
+        FBitmapOptions.ResampleFilter;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].ResampleMode :=
+        FBitmapOptions.ResampleMode;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].DrawMode := FBitmapOptions.DrawMode;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpTop] :=
+        FBitmapOptions.RepeatTop;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpBottom] :=
+        FBitmapOptions.RepeatBottom;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpLeft] :=
+        FBitmapOptions.RepeatLeft;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpRight] :=
+        FBitmapOptions.RepeatRight;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpMiddleHorizontal] :=
+        FBitmapOptions.RepeatMiddleHorizontal;
+      FBGRAMultiSliceScaling.SliceScalingArray[i].SliceRepeat[srpMiddleVertical] :=
+        FBitmapOptions.RepeatMiddleVertical;
+      if FBitmapOptions.AutoDetectRepeat then
+        FBGRAMultiSliceScaling.SliceScalingArray[i].AutodetectRepeat;
+    end;
+
+    { Calculate FDestRect }
+    FDestRect := CalculateDestRect(
+      FBGRAMultiSliceScaling.SliceScalingArray[0].BitmapWidth,
+      FBGRAMultiSliceScaling.SliceScalingArray[0].BitmapHeight, Width,
+      Height, FBitmapOptions.Stretch, FBitmapOptions.Proportional,
+      FBitmapOptions.Center);
+
+    { Draw in cache bitmaps }
+    FBGRAMultiSliceScaling.Draw(0, FBGRANormal, 0, 0, FDestRect.Right,
+      FDestRect.Bottom, Debug);
+    FBGRAMultiSliceScaling.Draw(1, FBGRAHover, 0, 0, FDestRect.Right,
+      FDestRect.Bottom, Debug);
+    FBGRAMultiSliceScaling.Draw(2, FBGRAActive, 0, 0, FDestRect.Right,
+      FDestRect.Bottom, Debug);
+    FBGRAMultiSliceScaling.Draw(3, FBGRADisabled, 0, 0, FDestRect.Right,
+      FDestRect.Bottom, Debug);
+
+    { Draw Text }
+    DrawText(FBGRANormal);
+    DrawText(FBGRAHover);
+    DrawText(FBGRAActive);
+    DrawText(FBGRADisabled);
+  end
+  else
+  begin
+    { Calculate FDestRect }
+    FDestRect := Rect(0, 0, Width, Height);
+
+    { Draw default style in cache bitmaps }
+    FBGRANormal.Rectangle(0, 0, Width, Height, BGRABlack, BGRA(0, 0, 255),
+      dmSet);
+    FBGRAHover.Rectangle(0, 0, Width, Height, BGRABlack, BGRA(0, 255, 0),
+      dmSet);
+    FBGRAActive.Rectangle(0, 0, Width, Height, BGRABlack, BGRA(255, 0, 0),
+      dmSet);
+    FBGRADisabled.Rectangle(0, 0, Width, Height, BGRABlack, BGRA(100, 100, 100),
+      dmSet);
+
+    { Draw Text }
+    DrawText(FBGRANormal);
+    DrawText(FBGRAHover);
+    DrawText(FBGRAActive);
+    DrawText(FBGRADisabled);
+  end;
+
+  {$IFDEF DEBUG}
+  FRenderCount += 1;
+  {$ENDIF}
+end;
+
+procedure TBCCustomImageButton.CMChanged(var Message: TLMessage);
+begin
+  if csReadingState in ControlState then
+    Exit;
+  RenderControl;
+end;
+
+{$IFDEF DEBUG}
+function TBCCustomImageButton.GetDebugText: string;
+begin
+  Result := 'Render: ' + IntToStr(FRenderCount) + ' Draw: ' + IntToStr(FDrawCount);
+end;
+
+{$ENDIF}
+
+procedure TBCCustomImageButton.DoMouseDown;
+begin
+  FFade.Mode := fmFadeOut;
+  inherited DoMouseDown;
+end;
+
+procedure TBCCustomImageButton.DoMouseUp;
+begin
+  FFade.Mode := fmFadeIn;
+  inherited DoMouseUp;
+end;
+
+procedure TBCCustomImageButton.DoMouseEnter;
+begin
+  FFade.Mode := fmFadeIn;
+  inherited DoMouseEnter;
+end;
+
+procedure TBCCustomImageButton.DoMouseLeave;
+begin
+  FFade.Mode := fmFadeOut;
+  inherited DoMouseLeave;
+end;
+
+constructor TBCCustomImageButton.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  {$IFDEF DEBUG}
+  FDrawCount := 0;
+  FRenderCount := 0;
+  {$ENDIF}
+  DisableAutoSizing;
+  Include(FControlState, csCreating);
+  BeginUpdate;
+  try
+    with GetControlClassDefaultSize do
+      SetInitialBounds(0, 0, CX, CY);
+    ControlStyle := ControlStyle + [csAcceptsControls];
+
+    FBitmapOptions := TBCImageButtonSliceScalingOptions.Create(Self);
+    {FBitmapOptions.Bitmap := TBGRABitmap.Create(1,4,BGRAWhite);
+    FBitmapOptions.Bitmap.SetPixel(0,0,BGRA(255,0,0,255));
+    FBitmapOptions.Bitmap.SetPixel(0,1,BGRA(0,255,0,255));
+    FBitmapOptions.Bitmap.SetPixel(0,2,BGRA(0,0,255,255));
+    FBitmapOptions.Bitmap.SetPixel(0,3,BGRA(100,100,100,255));}
+
+    FFade.Step := 15;
+    FFade.Mode := fmFadeOut;
+    FTimer := TTimer.Create(Self);
+    FTimer.Interval := 15;
+    FTimer.OnTimer := @Fade;
+
+  finally
+    Exclude(FControlState, csCreating);
+    EnableAutoSizing;
+    EndUpdate;
+  end;
+end;
+
+destructor TBCCustomImageButton.Destroy;
+begin
+  FTimer.Free;
+  if FBGRAMultiSliceScaling <> nil then
+    FreeAndNil(FBGRAMultiSliceScaling);
+  if FBGRANormal <> nil then
+    FreeAndNil(FBGRANormal);
+  if FBGRAHover <> nil then
+    FreeAndNil(FBGRAHover);
+  if FBGRAActive <> nil then
+    FreeAndNil(FBGRAActive);
+  if FBGRADisabled <> nil then
+    FreeAndNil(FBGRADisabled);
+  FreeAndNil(FBitmapOptions);
+  inherited Destroy;
+end;
+
+end.

+ 45 - 0
bcimagebutton_icon.lrs

@@ -0,0 +1,45 @@
+LazarusResources.Add('TBCImageButton','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#3#212'IDATH'#199#181#149#221'O[u'#24#199'?'#231#156#190#157#190#208'RXi'
+  +#203'{'#202'Z'#9'/'#206#189#168#25#163#9#146'it!.'#203#178#168#201#18#189#240
+  +'O'#208'hb'#136'&'#220#152'e&z'#225'LL'#140#23'^'#26'/'#188#210#16'1"'#14'_'
+  +#182#17#154#12'7H)'#208#21':^'#10#5#218'rN'#219's'#188#128#20#25's'#163'#>W'
+  +#191'<'#249'='#191#207#239#247#252#158#231#251#8#237#31#127#173#243'?'#154'X'
+  +'n'#128#0#8#133#252#129#247#27#246'y'#138'E'#148#217'i'#178#177'('#202'b'#18
+  +'='#155#5'Q"'#240't'''#199#250#250#24'M,s'#194#227'd*'#147''''#173#228#203#3
+  +#8#186#142#182#145#198#232#241#226#242#213#162'e6'#217#154#143#19#174#171#230
+  +#189'7/QSS'#195'Pl'#129#31'&'#162'|p'#170#157'w'#127#252#147#199#229'W'#242
+  +#156'='#255#225'.A@'#176#200#8'&3'#130#209#136'h'#181'a'#170#241#147#148']'
+  +#196'R'#235#4#172'FN4'#213'b'#151'-t5'#251#137#167'3DS'#235'e'#166'HUQ'#23
+  +#147'8'#141#18'/t='#139' '#128#166#131#6#252#158#202#17'l'#146#232'n'#246#3
+  +'p'#249'x'#136#193#169#248'#_Q'#2'h'#217#12#155'7FQ'#150#151#16'd+'#29#225'.'
+  +'lz'#30'A'#23#144#205'&:'#235#189#156'l'#244'#'#138'B)8'#224#174#160#193#229
+  +'`vm'#227#241#0#209'`'#160#162#187#23#132#237#3#238#2#247#19'k'#244#181'6'
+  +#243'b'#168#129#166'J'#199#158#192#129'+'#215'x'#169#247#12#129#170#138#131#1
+  +'0'#153'KK'#217'h'#224#242'3A.u'#4'0'#10' I'#210#190'@'#155'M'#230#141#183
+  +#223#225#234#23'W'#136'X-,g'#183#30'^'#214#15'6Z>q'#143'/'#223'z'#149#163#222
+  +'j'#226'K+L'#173'ex'#165'3'#132'$n'#183#140#174#235#20#139'EDQd-'#189'A'#177
+  +'X'#196'd'#183#243#201#200'8'#131'S'#241'G'#127'rf'#236'/'#150#127#25'b'#190
+  +#175#155'o"Q'#254'^'#203'r'#237'|'#184't'#184#166'i'#220#153'K'#16']\'#161
+  +#209'i'#165#202'n'#195'j'#181'bF'#163#191#231'8'#231'B'#13'|'#246#235#24#211
+  +#233#236'~@z'#248''''#182#146#243#248'.'#190#198#192#173#24#0#239#135#143#209
+  +'PYQ'#186#245#245#153#5#250#135'n'#162#22'5'#4#1'j,&'#130'N'#153'V'#183#157
+  +#142'#Nj'#157#14':'#238'E'#184#27'['#198#216#249#252'. '#23#185#133#185#182
+  +#30'g'#184#183'Dnq;x'#249#169'F'#0'n'''#238'Sa'#146#248'~2'#142'Z'#212'vR'#5
+  +#201#156'J2'#167'2'#156'L#'#144#192'g5a'#168#14'bt'#4'v'#181'H'#200'e'#144'C'
+  +'mX'#2#193'='#185#187#208#218#136'A'#146'X'#221#204#240#209#207'c'#168#249#2
+  +#13'.'#199#127'V'#139#14#204'gU'#230#20'mG'#177'v'#0#186'l'#3#179'y'#175#2#10
+  +#2']'#13'^4M'#227#211#223'"$6s'#164'29^'#239'l'#193'n2'#30'^M'#139#171'+$'#19
+  +#9'Fc'#9#6#167#23#0#152'\Z'#197'-'#155#232#239'='#137#244#175'f'#163',-'#218
+  +'1%'#185#192#245'o'#191'c'#194#229'cuK'#5#160'P'#212'8SWM'#208'{'#132'z'#167
+  +#157#145#153'$'#154#174'?'#225'<'#208'4'#162#235'9'#166#215'6K'#174#241#149
+  +#13'n'#198#226'('#138#194#217#163#245'\=w'#154#10#179#233#201#0#146',c'#11
+  +#181#238'e'#234#240'yd'#150#201#153'9'#20'E'#225'T'#157#135#175'.'#246#208'^'
+  +#227'.'#31'`tWa'#169#171#223#231'_'#200#170#12#252'1'#201#141';S'#164'R)'#204
+  +#5#149#11'N'#9'qb'#28#10#133#131'I'#197#129#198#160#174#177'5~'#131#249#145
+  +'a'#10'['#10#130' b'#170#172#164'*'#220#131#165'%tx@'#201#10'yr'#209'I'#178
+  +#209')r'#137'8j:'#141#236#245#227'z'#238'4r '#8#162#248#144#129'S'#214'S'#140
+  +#200#161'6'#228'P'#219'N'#249')'#20#210')'#10#27#27#168's'#211'X'#252#245#135
+  +#4'<hf3'#6#143#15#131#199#183']'#24#192'?'#168'"z'#17#202'#'#7'8'#0#0#0#0'IE'
+  +'ND'#174'B`'#130
+]);

+ 327 - 0
bclabel.pas

@@ -0,0 +1,327 @@
+{ Equivalent of standard lazarus TLabel but using BGRA Controls framework for text
+  render.
+
+  Functionality:
+  - Customizable background (gradients etc.)
+  - Customizable border (rounding etc.)
+  - FontEx (shadow, word wrap, etc.)
+
+  Copyright (C) 2012 Krzysztof Dibowski dibowski at interia.pl
+
+  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 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.
+
+  This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+
+unit BCLabel;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
+  BCBasectrls, BGRABitmap, BGRABitmapTypes, BCTypes, types;
+
+type
+
+  { TCustomBCLabel }
+
+  TCustomBCLabel = class(TBCStyleGraphicControl)
+  private
+    { Private declarations }
+    {$IFDEF DEBUG}
+    FRenderCount: Integer;
+    {$ENDIF}
+    FBackground: TBCBackground;
+    FBGRA: TBGRABitmapEx;
+    FBorder: TBCBorder;
+    FFontEx: TBCFont;
+    FRounding: TBCRounding;
+    procedure Render;
+    procedure SetRounding(AValue: TBCRounding);
+    procedure UpdateSize;
+    procedure SetBackground(AValue: TBCBackground);
+    procedure SetBorder(AValue: TBCBorder);
+    procedure SetFontEx(AValue: TBCFont);
+    procedure OnChangeProperty(Sender: TObject; Data: PtrInt);
+    procedure OnChangeFont(Sender: TObject; AData: PtrInt);
+  protected
+    procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
+      WithThemeSpace: boolean); override;
+    class function GetControlClassDefaultSize: TSize; override;
+    procedure TextChanged; override;
+  protected
+    {$IFDEF DEBUG}
+    function GetDebugText: String; override;
+    {$ENDIF}
+    procedure DrawControl; override;
+    procedure RenderControl; override;
+    function GetStyleExtension: String; override;
+  protected
+    { Protected declarations }
+    property AutoSize default True;
+    property Background: TBCBackground read FBackground write SetBackground;
+    property Border: TBCBorder read FBorder write SetBorder;
+    property FontEx: TBCFont read FFontEx write SetFontEx;
+    property Rounding: TBCRounding read FRounding write SetRounding;
+  public
+    { Public declarations }
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure UpdateControl; override; // Called by EndUpdate
+  published
+    { Published declarations }
+  end;
+
+  { TBCLabel }
+
+  TBCLabel = class(TCustomBCLabel)
+  published
+    property Action;
+    property Align;
+    property Anchors;
+    property AssignStyle;
+    property AutoSize;
+    property Background;
+    property Border;
+    property BorderSpacing;
+    property Caption;
+    property Cursor;
+    property Enabled;
+    property FontEx;
+    property Height;
+    property HelpContext;
+    property HelpKeyword;
+    property HelpType;
+    property Hint;
+    property Left;
+    property PopupMenu;
+    property Rounding;
+    property ShowHint;
+    property Tag;
+    property Top;
+    property Visible;
+    property Width;
+  end;
+
+procedure Register;
+
+implementation
+
+uses BCTools;
+
+procedure Register;
+begin
+  {$I bclabel_icon.lrs}
+  RegisterComponents('BGRA Controls',[TBCLabel]);
+end;
+
+{ TCustomBCLabel }
+
+procedure TCustomBCLabel.Render;
+var r: TRect;
+begin
+  if (csCreating in FControlState) or IsUpdating then
+    Exit;
+
+  FBGRA.NeedRender := False;
+
+  FBGRA.SetSize(Width, Height);
+  FBGRA.Fill(BGRAPixelTransparent); // Clear;
+  r := FBGRA.ClipRect;
+  CalculateBorderRect(FBorder,r);
+
+  RenderBackground(FBGRA.ClipRect, FBackground, TBGRABitmap(FBGRA), FRounding);
+  RenderBorder(r, FBorder, TBGRABitmap(FBGRA), FRounding);
+  RenderText(FBGRA.ClipRect, FFontEx, Caption, TBGRABitmap(FBGRA));
+
+  {$IFDEF DEBUG}
+  FRenderCount += 1;
+  {$ENDIF}
+end;
+
+procedure TCustomBCLabel.SetRounding(AValue: TBCRounding);
+begin
+  if FRounding = AValue then Exit;
+  FRounding.Assign(AValue);
+
+  RenderControl;
+  Invalidate;
+end;
+
+procedure TCustomBCLabel.UpdateSize;
+begin
+  InvalidatePreferredSize;
+  AdjustSize;
+end;
+