diff options
Diffstat (limited to 'karbon')
403 files changed, 55230 insertions, 0 deletions
diff --git a/karbon/AUTHORS b/karbon/AUTHORS new file mode 100644 index 00000000..859de51d --- /dev/null +++ b/karbon/AUTHORS @@ -0,0 +1,3 @@ +Rob Buis <buis@kde.org> +Tomislav Lukman <tomislav.lukman@ck.t-com.hr> +Benoit Vautrin <benoit.vautrin@free.fr> diff --git a/karbon/CHANGES b/karbon/CHANGES new file mode 100644 index 00000000..3241a4a5 --- /dev/null +++ b/karbon/CHANGES @@ -0,0 +1,115 @@ +Changes in trunk +These are changes that can not be backported, and will be available from KOffice 1.5 +- Changed version to 0.2.90 +- Added names of contributors +- Enabled right mouse click to zoom out of canvas, partially fixing bug 96944 +- Place gradient loading (and later also saving) in a general place (libraries) +- Karbon can load SVG and Gimp gradients +- How to bring back the overview window if you close it? (#111717) +- Rename plugins menu to "Effect" (#111618) +- Change Align Center (Vertical) to Align Middle and add some extra separators (#109520) +- Keybindings like krita, and other tweak (#108789) +- Always use this document at startup, Karbon has not way to stop doing this (#108755) + Add a basic karbon template +- Dockers now use the KoPalette library. This means a huge improvement when it comes to docker management. + This closes the following bugs (#91376, #111207, #60844) + +Changes after 1.4.2 (available from 1.4.3 if there will ever be one): +- Make paste operation undo:able (#115752) + +Changes after 1.4.1 (available from 1.4.2): +- Changed version to 0.2 +- Fixed loading and saving of text basepath and font properties +- Do not trigger text tracing/repaining if we are only initializing the options dialog +- Only repaint inside objects bounding boxes +- When dragging a path to place text along, pressing shift makes the path "jump" in 45 degree steps +- Create text with horizontal path when just clicking with texttool +- Always initialize with selected object when showing the tool dialog +- Only show tool dialog when an object is selected +- Made texttool selection changing (triggers views selection changed signal) +- Always repaint bounding rect of edited text when changed +- Set all shadow options properly in tool dialog +- Cancel tool when pressing cancel button +- When inserting a new object in front of another, set the new objects parent and invalidate the groups bounding box +- When grouping objects, remove all objects from their corresponding parent +- Enabling the group/ungroup menu item when selecting objects from layer list view +- The polyline tool was broken. When you clicked to place a point (after the first one), the point was always placed with x=0 +- Fix for karbon crashing on clicking the pattern button in the toolbox +- Make sure, items representing an object without a proper parent are removed as well +- Improved selection tool which now has the following abilities: + * left mouse click to select single object + * ctrl + left mouse click to add to current selection + * ctrl + right mouse click to remove from current selection + * ctrl + left mouse drag to add objects within selection rect to current selection + * ctrl + right mouse drag to remove objects within selection rect from current selection + * presssing shift while scaling makes scaling keeping the aspect ratio (adjusted to shape tool behaviour) +- Fix a drawing bug when selecting objects +- Object/layer listview is now better synced to the documents object hierarchy when deleting or grouping/ungrouping objects +- Enabled multi-selection within the layer listview +- Object/layer listview items get automatically selected when selecting their corresponding object with the selection tool +- Visiblity and locking states are now set correctly from the layer listview +- When embeded zoom the drawing so that it's completely visible +- Make this statusbar text label stretchable, so the rest of the labels won't jump around +- Filter SVG: Added reading of group names +- Filter SVG: Fix percentage loading error +- Filter SVG: Don't lock up on svg document loading +- Text object names are not loaded (#111269) +- Text stroke isn't loaded (#111268) +- Usability: Layers open themself -> only open layer list items when inserting them into list (#111206) +- Usability: Copy/Paste over layers is not consistent (#111203) +- Usability: Current layer looses selection (#111201) + - always select layer list item corresponding to active layer + - delete layer list items when undoing VLayerCommand + - do not allow to delete last layer (see also #111210) +- Layer deletion doesn't get saved (#111148) +- Crash when changing the color of more than one element (#111147) +- Export only exports the first layer (#111144) +- SVG import fails to recognise the svg use tag (#108245) +- Karbon svg export minor improvements (#108243) +- Pretty print SVG export please, indentation using spaces (#108126) +- KoUnitDoubleSpinBox has a design flaw (#106011) +- Karbon crashes when using text-tool (#51663) + +Changes after 1.4 (available from 1.4.1): +- Fix crash when inserting object in splitted view +- Fix incorrect display of the position in the statusbar +- Filter: AI: GCC 4 fix +- Crash on layer creation (#93903) +- Gradient widget crashes when cursor with pushed LMB leaves widget (#92976) +- Crashes when applying pattern to object (#77476) + Don't crash if the pattern doesn't have an image +- Karbon14 crashes often and does not load files (#69738) + Don't crash in VSmallPreview when there are more then one object selected +- Raising/Lowering layers has no effect (#68060) + + + + + +Changes after 1.3 XMas preview: +- Make sure we draw non-empty paths, otherwise we get extra, unwanted lines using non-AA + painter and in print preview. +- Hack to fix bug #70644 for karbon. However note this doesnt fix the total bug, just + for karbon. + +Changes after 1.3 RC1: +- make imported SVG's visible by default +- Karbon freezes when opening karbon file (#68499) +- fixed loading recent files +- update statusbar info while moving the selection using arrow keys +- delete key deletes selected object (#68062) +- fixed zooming into rectangular areas (#60842) +- fixed crash with polyline tool drawing + Ctrl key (#63981) + +Changes after 1.3 beta 1 : + +- new tool controller +- refactoring flattenpath cmd after wmf filter changes +- zooming fixes +- svg exporting uses document dimension, not dimension of + the active selection +- new style docker introduced, with dragable cliparts +- added aspect-ratio keeping way of scaling for select tool +- various ui tweaks, including new icons (Tomislav) +- improved behaviour for strokefill preview widget (Tomislav) +- speedups on large documents for the document tree widget diff --git a/karbon/COPYING.LIB b/karbon/COPYING.LIB new file mode 100644 index 00000000..cc6f3656 --- /dev/null +++ b/karbon/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + 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 Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +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 other code 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. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + 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, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser 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. +^L + 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. +^L + 6. As an exception to the Sections above, you may also combine 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) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) 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. + + d) 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. + + e) 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 materials to be 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. +^L + 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 with +this License. +^L + 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 Lesser 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. +^L + 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 +^L + 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/karbon/GRAPHICS_MEETING b/karbon/GRAPHICS_MEETING new file mode 100644 index 00000000..c5eaddd8 --- /dev/null +++ b/karbon/GRAPHICS_MEETING @@ -0,0 +1,9 @@ +Ideas from graphics meeting (but also in my head before it): + +- use QPainterPath, get rid of libart +- use color profiles/matching (krita?) +- get rid of the old freetype code to convert text to path, use + QPainterPath::addText instead. +- use koText for text boxes? +- improve printing, should be a lot better when we use QPainter(?) +- use real-time editing, for instance real-time changing of gradients diff --git a/karbon/IDEAS b/karbon/IDEAS new file mode 100644 index 00000000..a5ce652d --- /dev/null +++ b/karbon/IDEAS @@ -0,0 +1,26 @@ +Food for thought: +================= +CAGD: +- http://softsurfer.com/algorithms.htm +- Guru's Lair Cubic Spline Library + http://www.tinaja.com/cubic01.html +- Graphics Gems Repository + http://www.acm.org/tog/GraphicsGems/ +- General polygon clipper library (gpc) + http://www.cs.man.ac.uk/~amurta/software/index.html +- Magic Software + http://www.magic-software.com/ +- FAQ for comp.graphics.algorithms: + http://www.landfield.com/faqs/graphics/algorithms-faq/ +- NEC Research Index + http://citeseer.nj.nec.com/cs +- Preprints + http://xxx.lanl.gov/archive/cs/intro.html +- Graphics Paper + http://www.graphicspapers.com/ + +Postscript: +- Adobe Illustrator Fileformat Specification: + http://partners.adobe.com/asn/developer/PDFS/TN/5007.AI7FileFormat.pdf +- Postscript Specs (since .AI is basically .PS): + http://partners.adobe.com/asn/developer/technotes.html#postscript diff --git a/karbon/Makefile.am b/karbon/Makefile.am new file mode 100644 index 00000000..db51231d --- /dev/null +++ b/karbon/Makefile.am @@ -0,0 +1,61 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOTEXT_INCLUDES) $(KOPALETTE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir) \ + -I$(srcdir)/commands \ + -I$(srcdir)/core \ + -I$(srcdir)/dialogs \ + -I$(srcdir)/dockers \ + -I$(srcdir)/render \ + -I$(srcdir)/visitors \ + -I$(srcdir)/widgets \ + $(all_includes) + +SUBDIRS = commands visitors core shapes widgets dialogs dockers render . tools plugins data pics templates + +lib_LTLIBRARIES = libkarboncommon.la +kde_module_LTLIBRARIES = libkarbonpart.la + +libkarboncommon_la_SOURCES = karbon_factory.cc karbon_resourceserver.cc karbon_part.cc karbon_part_iface.cc karbon_part_iface.skel karbon_view.cc karbon_view_iface.cc karbon_view_iface.skel karbon_drag.cpp karbon_grid_data.cpp karbon_tool_registry.cc karbon_tool_factory.cc vtoolcontroller.cc vtool.cc + +libkarboncommon_la_LDFLAGS = $(KDE_RPATH) $(LIBFREETYPE_RPATH) $(LIBMAGICK_LDFLAGS) -no-undefined +libkarboncommon_la_LIBADD = $(LIB_KOFFICECORE) $(LIB_KOFFICEUI) $(LIB_KOPALETTE) $(LIB_KOPAINTER) $(LIB_KOTEXT) \ + dockers/libkarbondockers.la \ + widgets/libkarbonwidgets.la \ + render/libvpainter.la \ + render/xrgbrender/libkarbonxrgbrender.la \ + core/libkarboncore.la \ + shapes/libkarbonshapes.la \ + commands/libkarboncommands.la \ + visitors/libkarbonvisitors.la \ + dialogs/libkarbondialogs.la \ + $(LIBART_LIBS) \ + $(LIBFONTCONFIG_LIBS) \ + $(LIBMAGICK_LIBS) \ + $(LIBFREETYPE_LIBS) + +libkarbonpart_la_SOURCES = karbon_factory_init.cc +libkarbonpart_la_LDFLAGS = $(KDE_PLUGIN) $(LIBFREETYPE_RPATH) +libkarbonpart_la_LIBADD = libkarboncommon.la + +bin_PROGRAMS = +kdeinit_LTLIBRARIES = karbon.la +karbon_la_SOURCES = main.cc +karbon_la_LDFLAGS = $(all_libraries) -module -avoid-version +karbon_la_LIBADD = libkarboncommon.la + +noinst_HEADERS = \ + karbon_factory.h \ + karbon_part.h \ + karbon_part_iface.h \ + karbon_view.h \ + karbon_drag.h \ + vtoolcontroller.h \ + vtool.h + +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) data/*.rc >> rc.cpp + $(XGETTEXT) rc.cpp *.cpp *.cc */*.cc tools/*.h plugins/*/*.cc -o $(podir)/karbon.pot + +include $(top_srcdir)/admin/Doxyfile.am + diff --git a/karbon/README b/karbon/README new file mode 100644 index 00000000..14f1546e --- /dev/null +++ b/karbon/README @@ -0,0 +1,50 @@ +Karbon14 is a vector graphics application within koffice. + + +Object hierarchy: +----------------- + + +- vdocument + | + +- vcomposite--+- (shapes) + | +vobject-+- vtext + | + +- vgroup-+- vlayer + + +Files and directories: +---------------------- +commands/ + Undo/redo operations. + +core/ + Essential data structures. + +data/ + KDE data. + +dialogs/ + Dialogs. + +dockers/ + Dockers. + +pics/ + Icons and grafx. + +render/ + Everything related to painting + +shapes/ + The basic shapes like ellipse and rectangle etc. + Shapes are nothing more than paths. + +tests/ + Demonstration karbon files. + +tools/ + Stuff you can do with the mouse. + +widgets/ + Widgets. diff --git a/karbon/TODO b/karbon/TODO new file mode 100644 index 00000000..9c268232 --- /dev/null +++ b/karbon/TODO @@ -0,0 +1,101 @@ +From the usability review of Thomas Zander +------------------------------------------ + +* Toolbars + - Toolbars should be persistent ---- + - toolbox to the left by default ---- + +* Toolbox + - select tool dialog has title "insert star" DONE + - difficult to see which tool is selected ---- + - clicking the "14" icon does not unselect previous tool DONE + - add kbd shortcuts to the tools ---- + - make 'ESC' select the 'Select tool' ---- + + + + +BIG TOPICS: +1) create a consistent tool/plugin system + plugin input: + - canvas (drawing, connecting to mouse/keyboard signals) + plugin output: + - icon + - help text + - options widget + - command + - kaction? +2) selection redesign + - unify object and or node selection? + - achieve tight selection (exact selection-object collision test) +3) reintroduce nodetool +4) make VObject leaner +5) introduce renderstack. And dont forget to rewrite shadoweffect to use it. + +GUI: +- remove the dialogs which show up when double clicking the strokefillpreview, this job is done + by "color manager" docker +- other koffice apps have widgts that may of interest to us, for instance in kpresenter. We should + try to reuse them. +- make a UI for the node manipulation tool. +- rework the stroke/fill docker with preview on the document and apply button. +- Find a better way to select a color than the color manager. Maybe a popup ? +- gradient widget: maybe turn the midpoint arrows to black or 3d triangles like in gimp or illu +- gradient widget: better separate the midpoint arrows from the color stop triangles: put them + above the gradient bar like in adobe products. the current situation is a bit nasty + with near together midpoints and colorstops +- gradient widget: the midpoint arrows are currently hard to hit and modify + +REAL BUGS: +- patterns dont zoom +- VSelectionTool has an offset error relative to the handle nodes in the VSelection. +- fix i18n singular/plural +- crashes in vtext +- make curve1To, curve2To work +- vpolylinetool creates beziers where it could create lines +- Selections can't be undone/redone because there are no selection commands. + Add a VSelectNodeCmd and/or a VSelectCmd. (See bug #60438) + +TODO: +- make pattern coords absolute and not relative to the shape +- VImage +- VPattern like VImage with embedded binaries instead of paths +- bring text support back, ideally using fontconfig and freetype, and no xft. +- improve printing (specifically printing of gradient and pattern fill), + should go along with porting to qt4/the new rendering framework +- select first/last segment's knot if one of each other's knot is selected +- allow for multiple strokes and fills in VPath which get rendered in the order they occur. +- use inside/intersection tests in vpath::combine() for changing winding. +- change flatness test in intersection code to a estimation used in gems code. otherwise + if the 2 input curves are the same our code runs forever. +- make VSelection a state pattern +- try to abstract rendering even more, preferably using kpainter abstraction. +- make layers tree robust, efficient and scalable. +- write odf enhanced-path parser (use some code from svgpathparser in lib) + +WISHLIST: +- krita export filter (with layers) +- add a nice grid-like shape like in Illu and webdraw +- pdf import filter (based on poppler) + +OPTIMIZATION: +- in VShapeTool and all manipulation tools: store temporary objects so one doesnt + have to recalculate/regenerate those for second draw() (erasing old shape) +- make fill/stroke shared so copying for undo/redo is more efficient. Also potentially + apply this to file format (like OOo does). +- transform() bbox too and dont recalculate it +- check places we use sqrt() if these are really necessary (lenny) + +MAKE IT NICE: +- can't we pass VTool::draw() a painter inseatd of each tool creating a painter itself? +- remove V*Tool::refreshUnit(). call this directly via dialog() instead +- pass all dialogs a parent +- think about using ghostscript's flatten algo (see comments in vflatten.cc) +- why represent opacity as float, not as short? +- introduce our own "Color drag" class, since we have in addition to rgb also opacity, + and maybe also gradient info could be dragged later. + +NEW IDEAS: +- make VDocument a KoDocument? +- use KParts::plugin for tools? + diff --git a/karbon/commands/Makefile.am b/karbon/commands/Makefile.am new file mode 100644 index 00000000..fb5ac24a --- /dev/null +++ b/karbon/commands/Makefile.am @@ -0,0 +1,55 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOFFICECORE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../visitors \ + $(all_includes) + +noinst_LTLIBRARIES = libkarboncommands.la + +noinst_HEADERS = \ + valigncmd.h \ + vbooleancmd.h \ + vcleanupcmd.h \ + vclipartcmd.h \ + vclosepathcmd.h \ + vcommand.h \ + vdeletecmd.h \ + vdistributecmd.h \ + vfillcmd.h \ + vflattencmd.h \ + vgroupcmd.h \ + vdeletenodescmd.h \ + vlayercmd.h \ + vreplacingcmd.h \ + vshapecmd.h \ + vstrokecmd.h \ + vtransformcmd.h \ + vinsertcmd.h \ + vungroupcmd.h \ + vzordercmd.h + +libkarboncommands_la_SOURCES = \ + valigncmd.cc \ + vbooleancmd.cc \ + vcleanupcmd.cc \ + vclipartcmd.cc \ + vclosepathcmd.cc \ + vcommand.cc \ + vdeletecmd.cc \ + vdistributecmd.cc \ + vfillcmd.cc \ + vflattencmd.cc \ + vgroupcmd.cc \ + vdeletenodescmd.cc \ + vlayercmd.cc \ + vreplacingcmd.cc \ + vshapecmd.cc \ + vstrokecmd.cc \ + vtransformcmd.cc \ + vinsertcmd.cc \ + vungroupcmd.cc \ + vzordercmd.cc + +libkarboncommands_la_METASOURCES = \ + AUTO + diff --git a/karbon/commands/valigncmd.cc b/karbon/commands/valigncmd.cc new file mode 100644 index 00000000..9e6392a1 --- /dev/null +++ b/karbon/commands/valigncmd.cc @@ -0,0 +1,87 @@ +/* This file is doc of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <klocale.h> + +#include "valigncmd.h" +#include "vtransformcmd.h" +#include "vdocument.h" +#include "vselection.h" + +#include <kdebug.h> + +VAlignCmd::VAlignCmd( VDocument *doc, Align align ) + : VCommand( doc, i18n( "Align Objects" ) ), m_align( align ) +{ + m_trafoCmds.setAutoDelete( true ); +} + +VAlignCmd::~VAlignCmd() +{ +} + +void +VAlignCmd::execute() +{ + if( document()->selection()->objects().count() == 0 ) + return; + double dx, dy; + KoRect bbox; + KoRect r; + if( document()->selection()->objects().count() == 1 ) + r = document()->boundingBox(); + else + r = document()->selection()->boundingBox(); + VObjectList objs = document()->selection()->objects(); + VObjectListIterator itr( objs ); + VTranslateCmd *trafoCmd = 0L; + for( ; itr.current() ; ++itr ) + { + document()->selection()->clear(); + bbox = itr.current()->boundingBox(); + switch( m_align ) + { + case ALIGN_HORIZONTAL_LEFT : dx = r.topLeft().x() - bbox.topLeft().x(); dy = 0; break; + case ALIGN_HORIZONTAL_CENTER: dx = r.center().x() - bbox.center().x(); dy = 0; break; + case ALIGN_HORIZONTAL_RIGHT : dx = r.topRight().x() - bbox.topRight().x(); dy = 0; break; + case ALIGN_VERTICAL_TOP : dx = 0; dy = r.bottomRight().y() - bbox.bottomRight().y(); break; + case ALIGN_VERTICAL_CENTER : dx = 0; dy = r.center().y() - bbox.center().y(); break; + case ALIGN_VERTICAL_BOTTOM : dx = 0; dy = r.topLeft().y() - bbox.topLeft().y(); break; + }; + document()->selection()->append( itr.current() ); + trafoCmd = new VTranslateCmd( document(), dx, dy ); + m_trafoCmds.append( trafoCmd ); + trafoCmd->execute(); + } + itr.toFirst(); + for( ; itr.current() ; ++itr ) + document()->selection()->append( itr.current() ); + setSuccess( true ); +} + +void +VAlignCmd::unexecute() +{ + QPtrListIterator<VTranslateCmd> itr( m_trafoCmds ); + for( ; itr.current() ; ++itr ) + itr.current()->unexecute(); + setSuccess( false ); +} + diff --git a/karbon/commands/valigncmd.h b/karbon/commands/valigncmd.h new file mode 100644 index 00000000..9fd8bf09 --- /dev/null +++ b/karbon/commands/valigncmd.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VALIGNCMD_H__ +#define __VALIGNCMD_H__ + +#include "vcommand.h" + +class VTranslateCmd; + +// Align objects... + +class VAlignCmd : public VCommand +{ +public: + enum Align + { + ALIGN_HORIZONTAL_LEFT, + ALIGN_HORIZONTAL_CENTER, + ALIGN_HORIZONTAL_RIGHT, + ALIGN_VERTICAL_BOTTOM, + ALIGN_VERTICAL_CENTER, + ALIGN_VERTICAL_TOP + }; + VAlignCmd( VDocument *doc, Align align ); + virtual ~VAlignCmd(); + + virtual void execute(); + virtual void unexecute(); + +protected: + Align m_align; + QPtrList<VTranslateCmd> m_trafoCmds; +}; + +#endif + diff --git a/karbon/commands/vbooleancmd.cc b/karbon/commands/vbooleancmd.cc new file mode 100644 index 00000000..a97fefe9 --- /dev/null +++ b/karbon/commands/vbooleancmd.cc @@ -0,0 +1,240 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qptrlist.h> +#include <qvaluelist.h> + +#include <klocale.h> + +#include "vbooleancmd.h" +#include "vpath.h" +#include "vsegment.h" +#include "vselection.h" +#include "vdocument.h" + +VBooleanCmd::VBooleanCmd( VDocument *doc, VBooleanType type ) + : VCommand( doc, i18n( "Boolean Operation" ) ) +{ + m_selection = document()->selection()->clone(); + m_type = type; +} + +VBooleanCmd::~VBooleanCmd() +{ + delete( m_selection ); +} + +void +VBooleanCmd::execute() +{ + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { +// TODO: pair wise visiting. + } + +// document()->append( ); + document()->selection()->clear(); +} + +void +VBooleanCmd::unexecute() +{ +} + +bool +VBooleanCmd::visit( VObject& object1, VObject& object2 ) +{ + m_path1 = 0L; + m_path2 = 0L; + object1.accept( *this ); + object2.accept( *this ); + + return success(); +} + +void +VBooleanCmd::visitVSubpath( VSubpath& path ) +{ + if( m_path1 == 0L ) + m_path1 = &path; + else if( m_path2 == 0L ) + { + m_path2 = &path; + + // intersection parameters (t): + VParamList params1; + VParamList params2; + VParamList::iterator pItr; + + double prevParam; + + m_path1->first(); + + // ommit "begin" segment: + while( m_path1->next() ) + { + params1.clear(); + + m_path2->first(); + + // ommit "begin" segment: + while( m_path2->next() ) + { + params2.clear(); + + recursiveSubdivision( + *m_path1->current(), 0.0, 1.0, + *m_path2->current(), 0.0, 1.0, + params1, params2 ); + + qHeapSort( params2 ); + + prevParam = 0.0; + + // walk down all intersection params and insert knots: + for( pItr = params2.begin(); pItr != params2.end(); ++pItr ) + { + m_path2->insert( + m_path2->current()->splitAt( + ( *pItr - prevParam )/( 1.0 - prevParam ) ) ); + + m_path2->next(); + prevParam = *pItr; + } + } + + qHeapSort( params1 ); + + prevParam = 0.0; + + // walk down all intersection params and insert knots: + for( pItr = params1.begin(); pItr != params1.end(); ++pItr ) + { + m_path1->insert( + m_path1->current()->splitAt( + ( *pItr - prevParam )/( 1.0 - prevParam ) ) ); + + m_path1->next(); + prevParam = *pItr; + } + } + } +} + +void +VBooleanCmd::recursiveSubdivision( + const VSegment& segment1, double t0_1, double t1_1, + const VSegment& segment2, double t0_2, double t1_2, + VParamList& params1, VParamList& params2 ) +{ + if( + !segment1.boundingBox().intersects( + segment2.boundingBox() ) ) + { + return; + } + + if( segment1.isFlat() ) + { + // calculate intersection of line segments: + if( segment2.isFlat() ) + { + KoPoint v1 = segment1.knot() - segment1.prev()->knot(); + KoPoint v2 = segment2.knot() - segment2.prev()->knot(); + + double det = v2.x() * v1.y() - v2.y() * v1.x(); + + if( 1.0 + det == 1.0 ) + return; + else + { + KoPoint v = segment2.prev()->knot() - segment1.prev()->knot(); + const double one_det = 1.0 / det; + + double t1 = one_det * ( v2.x() * v.y() - v2.y() * v.x() ); + double t2 = one_det * ( v1.x() * v.y() - v1.y() * v.x() ); + + if ( t1 < 0.0 || t1 > 1.0 || t2 < 0.0 || t2 > 1.0 ) + return; + + params1.append( t0_1 + t1 * ( t1_1 - t0_1 ) ); + params2.append( t0_2 + t2 * ( t1_2 - t0_2 ) ); + } + } + else + { + // "copy segment" and split it at midpoint: + VSubpath path2( segment2 ); + path2.insert( path2.current()->splitAt( 0.5 ) ); + + double mid2 = 0.5 * ( t0_2 + t1_2 ); + + recursiveSubdivision( + *path2.current(), t0_2, mid2, + segment1, t0_1, t1_1, params2, params1 ); + recursiveSubdivision( + *path2.next(), mid2, t1_2, + segment1, t0_1, t1_1, params2, params1 ); + } + } + else + { + // "copy segment" and split it at midpoint: + VSubpath path1( segment1 ); + path1.insert( path1.current()->splitAt( 0.5 ) ); + + double mid1 = 0.5 * ( t0_1 + t1_1 ); + + if( segment2.isFlat() ) + { + recursiveSubdivision( + *path1.current(), t0_1, mid1, + segment2, t0_2, t1_2, params1, params2 ); + recursiveSubdivision( + *path1.next(), mid1, t1_1, + segment2, t0_2, t1_2, params1, params2 ); + } + else + { + // "copy segment" and split it at midpoint: + VSubpath path2( segment2 ); + path2.insert( path2.current()->splitAt( 0.5 ) ); + + double mid2 = 0.5 * ( t0_2 + t1_2 ); + + recursiveSubdivision( + *path1.current(), t0_1, mid1, + *path2.current(), t0_2, mid2, params1, params2 ); + recursiveSubdivision( + *path1.next(), mid1, t1_1, + *path2.current(), t0_2, mid2, params1, params2 ); + + recursiveSubdivision( + *path1.prev(), t0_1, mid1, + *path2.next(), mid2, t1_2, params1, params2 ); + recursiveSubdivision( + *path1.next(), mid1, t1_1, + *path2.current(), mid2, t1_2, params1, params2 ); + } + } +} + diff --git a/karbon/commands/vbooleancmd.h b/karbon/commands/vbooleancmd.h new file mode 100644 index 00000000..4320f0d2 --- /dev/null +++ b/karbon/commands/vbooleancmd.h @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VBOOLEANCMD_H__ +#define __VBOOLEANCMD_H__ + + +#include <qvaluelist.h> + +#include "vcommand.h" + +class VSubpath; +class VSegment; +class VSelection; + + +class VBooleanCmd : public VCommand +{ +public: + enum VBooleanType + { + intersect, + shape_union, + shape_xor, + substract + }; + + VBooleanCmd( VDocument* doc, VBooleanType type = intersect ); + virtual ~VBooleanCmd(); + + virtual void execute(); + virtual void unexecute(); + + + // We can only visit object pairs. + virtual bool visit( VObject& /*object*/ ) + { + return false; + } + + // A pair visit() function. + bool visit( VObject& object1, VObject& object2 ); + + + virtual void visitVSubpath( VSubpath& path ); + +protected: + typedef QValueList<double> VParamList; + + void recursiveSubdivision( + const VSegment& segment1, double t0_1, double t1_1, + const VSegment& segment2, double t0_2, double t1_2, + VParamList& params1, VParamList& params2 ); + + + VSelection* m_selection; + + VBooleanType m_type; + + VSubpath* m_path1; + VSubpath* m_path2; +}; + +#endif + diff --git a/karbon/commands/vcleanupcmd.cc b/karbon/commands/vcleanupcmd.cc new file mode 100644 index 00000000..6df53601 --- /dev/null +++ b/karbon/commands/vcleanupcmd.cc @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vcleanupcmd.h" +#include "vlayer.h" +#include "vdocument.h" + +VCleanUpCmd::VCleanUpCmd( VDocument *doc ) + : VCommand( doc, i18n( "Clean Up" ) ) +{ +} + +VCleanUpCmd::~VCleanUpCmd() +{ +} + +void +VCleanUpCmd::execute() +{ + visit( *document() ); +} + +void +VCleanUpCmd::unexecute() +{ +} + +void +VCleanUpCmd::visitVLayer( VLayer& layer ) +{ + VObjectListIterator itr( layer.objects() ); + for( ; itr.current(); ++itr ) + { + if( itr.current()->state() == VObject::deleted ) + { + delete( itr.current() ); + layer.take( *itr.current() ); + } + } +} diff --git a/karbon/commands/vcleanupcmd.h b/karbon/commands/vcleanupcmd.h new file mode 100644 index 00000000..9acce3d3 --- /dev/null +++ b/karbon/commands/vcleanupcmd.h @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCLEANUPCMD_H__ +#define __VCLEANUPCMD_H__ + +#include "vcommand.h" + +class VLayer; + +/* + * This visitor visits all layers and destroys all objects + * that are in a deleted state. Note that this operation + * is permanent! + */ +class VCleanUpCmd : public VCommand +{ +public: + VCleanUpCmd( VDocument *doc ); + virtual ~VCleanUpCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual void visitVLayer( VLayer& layer ); +}; + +#endif + diff --git a/karbon/commands/vclipartcmd.cc b/karbon/commands/vclipartcmd.cc new file mode 100644 index 00000000..42ce3a1d --- /dev/null +++ b/karbon/commands/vclipartcmd.cc @@ -0,0 +1,65 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vclipartcmd.h" +#include "vdocument.h" +#include "vselection.h" + +VClipartCmd::VClipartCmd( VDocument* doc, const QString& name, VObject* clipart ) + : VCommand( doc, name ), m_clipart( clipart->clone() ), m_executed( false ) +{ +} + +void +VClipartCmd::execute() +{ + if( !m_clipart ) + return; + + if( m_clipart->state() == VObject::deleted ) + m_clipart->setState( VObject::normal ); + else + { + m_clipart->setState( VObject::normal ); + document()->append( m_clipart ); + document()->selection()->clear(); + document()->selection()->append( m_clipart ); + } + + m_executed = true; + + setSuccess( true ); +} + +void +VClipartCmd::unexecute() +{ + if( !m_clipart ) + return; + + document()->selection()->take( *m_clipart ); + + m_clipart->setState( VObject::deleted ); + + m_executed = false; + + setSuccess( false ); +} + diff --git a/karbon/commands/vclipartcmd.h b/karbon/commands/vclipartcmd.h new file mode 100644 index 00000000..37e809a2 --- /dev/null +++ b/karbon/commands/vclipartcmd.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCLIPARTCMD_H__ +#define __VCLIPARTCMD_H__ + +#include "vcommand.h" + +class VClipartCmd : public VCommand +{ +public: + VClipartCmd( VDocument* doc, const QString& name, VObject* clipart ); + virtual ~VClipartCmd() {} + + virtual void execute(); + virtual void unexecute(); + virtual bool isExecuted() { return m_executed; } + + virtual bool changesSelection() const { return true; } + +private: + VObject* m_clipart; + bool m_executed; +}; + +#endif + diff --git a/karbon/commands/vclosepathcmd.cc b/karbon/commands/vclosepathcmd.cc new file mode 100644 index 00000000..3afe6195 --- /dev/null +++ b/karbon/commands/vclosepathcmd.cc @@ -0,0 +1,36 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003, 2004 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vclosepathcmd.h" +#include <klocale.h> + +#include <core/vpath.h> + +VClosePathCmd::VClosePathCmd( VDocument *doc ) + : VReplacingCmd( doc, i18n( "Close Path" ) ) +{ +} + +void +VClosePathCmd::visitVSubpath( VSubpath& path ) +{ + path.close(); + setSuccess(); +} + diff --git a/karbon/commands/vclosepathcmd.h b/karbon/commands/vclosepathcmd.h new file mode 100644 index 00000000..a7e02363 --- /dev/null +++ b/karbon/commands/vclosepathcmd.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003, 2004 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __CLOSEPATHCMD_H__ +#define __CLOSEPATHCMD_H__ + +#include <commands/vreplacingcmd.h> + +class VSubpath; + +class VClosePathCmd : public VReplacingCmd +{ +public: + VClosePathCmd( VDocument *doc ); + virtual ~VClosePathCmd() {} + + virtual void visitVSubpath( VSubpath& path ); +}; + +#endif + diff --git a/karbon/commands/vcommand.cc b/karbon/commands/vcommand.cc new file mode 100644 index 00000000..7ba4c4be --- /dev/null +++ b/karbon/commands/vcommand.cc @@ -0,0 +1,384 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "kaction.h" +#include "klocale.h" + +#include "vcommand.h" +#include "karbon_part.h" + + +VCommandHistory::VCommandHistory( KarbonPart* part ) + : m_part( part ), m_undoLimit( 50 ), m_redoLimit( 30 ), m_savedPos( 0 ) +{ + m_commands.setAutoDelete( true ); + + m_undo = KStdAction::undo( this, SLOT( undo() ), m_part->actionCollection(), "koffice_undo" ); + m_redo = KStdAction::redo( this, SLOT( redo() ), m_part->actionCollection(), "koffice_redo" ); + + clear(); +} + +VCommandHistory::~VCommandHistory() +{ +} + +void +VCommandHistory::clear() +{ + if( m_savedPos != int( m_commands.count() - 1 ) ) + m_savedPos = -1; + else + m_savedPos = 0; + + m_commands.clear(); + + emit historyCleared(); + + if( m_undo != 0 ) + { + m_undo->setEnabled( false ); + m_undo->setText( i18n( "&Undo" ) ); + } + + if( m_redo != 0 ) + { + m_redo->setEnabled( false ); + m_redo->setText( i18n( "&Redo" ) ); + } +} + +void +VCommandHistory::addCommand( VCommand* command, bool execute ) +{ + if( command == 0L ) + return; + + if( !m_commands.isEmpty() ) + { + while( m_commands.last() && !m_commands.last()->success() ) + { + m_commands.removeLast(); + emit lastCommandRemoved(); + } + } + + m_commands.append( command ); + kdDebug(38000) << "History: new command: " << m_commands.findRef( command ) << endl; + + if( execute ) + { + command->execute(); + emit commandExecuted( command ); + } + + updateActions(); + + emit commandAdded( command ); +} + +void +VCommandHistory::setUndoLimit( unsigned int limit ) +{ + m_undoLimit = limit; + clipCommands(); +} + +void +VCommandHistory::setRedoLimit( unsigned int limit ) +{ + m_redoLimit = limit; + clipCommands(); +} + +void +VCommandHistory::undo() +{ + int i = m_commands.count() - 1; + + if( i == -1 ) + return; + + while( ( i >= 0 ) && !( m_commands.at( i )->success() ) ) + { + i--; + } + + if( i < 0 ) + return; + + VCommand* cmd = m_commands.at( i ); + + cmd->unexecute(); + + emit commandExecuted( cmd ); + + emit commandExecuted(); + + clipCommands(); + + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::redo() +{ + int i = m_commands.count() - 1; + + if( i == -1 ) + return; + + while( ( i >= 0 ) && !( m_commands.at( i )->success() ) ) + { + i--; + } + + i++; + + if( i >= int( m_commands.count() ) ) + return; + + VCommand* cmd; + + if( ( cmd = m_commands.at( i ) ) == 0L ) + return; + + cmd->execute(); + + emit commandExecuted( cmd ); + emit commandExecuted(); + + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::undo( VCommand* command ) +{ + if( ( m_commands.findRef( command ) == -1 ) || ( !command->success() ) ) + return; + + command->unexecute(); + + emit commandExecuted( command ); + emit commandExecuted(); + + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::redo( VCommand* command ) +{ + if( ( m_commands.findRef( command ) == -1 ) || ( command->success() ) ) + return; + + command->execute(); + + emit commandExecuted( command ); + emit commandExecuted(); + + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::undoAllTo( VCommand* command ) +{ + int to; + + if( ( to = m_commands.findRef( command ) ) == -1 ) + return; + + int i = m_commands.count() - 1; + + VCommand* cmd; + + while( i > to ) + { + cmd = m_commands.at( i-- ); + + if( cmd->success() ) + { + cmd->unexecute(); + emit commandExecuted( cmd ); + } + } + + emit commandExecuted(); + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::redoAllTo( VCommand* command ) +{ + int to; + + if( ( to = m_commands.findRef( command ) ) == -1 ) + return; + + int i = 0; + + VCommand* cmd; + + while( i <= to ) + { + cmd = m_commands.at( i++ ); + + if( !cmd->success() ) + { + cmd->execute(); + emit commandExecuted( cmd ); + } + } + + emit commandExecuted(); + updateActions(); + + m_part->repaintAllViews(); +} + +void +VCommandHistory::documentSaved() +{ + // I don't know how to make this work... This is a temporary hack... + // Maybe remove all undone commands before the current one ? + int i = m_commands.count() - 1; + + while( ( i >= 0 ) && !( m_commands.at( i )->success() ) ) + { + i--; + } + + i++; + + m_savedPos = i; +} + +void +VCommandHistory::clipCommands() +{ + while( m_commands.count() > m_undoLimit ) + { + if( m_commands.removeFirst() ) + m_savedPos--, emit firstCommandRemoved(); + } + + int i = 0; + + int c = m_commands.count(); + + while( ( i < c ) && ( !m_commands.at( c - 1 - i )->success() ) ) + { + i++; + } + + i = i - m_redoLimit; + + for( int j = 0; j < i; j++ ) + { + if( m_commands.removeLast() ) + emit lastCommandRemoved(); + } +} + +void +VCommandHistory::updateActions() +{ + if( m_commands.count() == 0 ) + { + if( m_undo != 0 ) + { + m_undo->setEnabled( false ); + m_undo->setText( i18n( "&Undo" ) ); + } + + if( m_redo != 0 ) + { + m_redo->setEnabled( false ); + m_redo->setText( i18n( "&Redo" ) ); + } + + return; + } + + int i = m_commands.count() - 1; + + while( ( i >= 0 ) && !( m_commands.at( i )->success() ) ) + { + i--; + } + + if( m_undo != 0 ) + { + if( i < 0 ) + { + m_undo->setEnabled( false ); + m_undo->setText( i18n( "&Undo" ) ); + } + else + { + m_undo->setEnabled( true ); + m_undo->setText( i18n( "&Undo: " ) + m_commands.at( i )->name() ); + } + } + + if( m_redo != 0 ) + { + if( ++i == int( m_commands.count() ) ) + { + m_redo->setEnabled( false ); + m_redo->setText( i18n( "&Redo" ) ); + } + else + { + m_redo->setEnabled( true ); + m_redo->setText( i18n( "&Redo: " ) + m_commands.at( i )->name() ); + } + } + + if( m_savedPos >= 0 ) + { + for( i = 0; i < m_savedPos; i++ ) + { + if( !m_commands.at( i )->success() ) + return; + } + + for( i = m_savedPos; i < int( m_commands.count() ); i++ ) + { + if( m_commands.at( i )->success() ) + return; + } + + emit documentRestored(); + } +} + +#include "vcommand.moc" + diff --git a/karbon/commands/vcommand.h b/karbon/commands/vcommand.h new file mode 100644 index 00000000..254e27eb --- /dev/null +++ b/karbon/commands/vcommand.h @@ -0,0 +1,318 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOMMAND_H__ +#define __VCOMMAND_H__ + + +//#include <assert.h> + +#include <qobject.h> +#include <qptrlist.h> + +#include "vvisitor.h" + +class VDocument; +class KarbonPart; +class KAction; + +/** + * The base class for all karbon commands. + * + * It basically defines the common interface that all commands should implement. + */ +class VCommand : public VVisitor +{ +public: + /** + * Constructs a new command. + * + * @param doc the document the command should work on + * @param name the name of the command (appears in command history) + * @param icon the icon of the command (appears in command history) + */ + VCommand( VDocument* doc, const QString& name, const QString& icon = "14_action" ) + : m_document( doc ), m_name( name ), m_icon( icon ) + { +// A crash because of an assert() is not much better than an crash because of a null +// pointer. Allowing null pointers allows the usage of the vitors ascpect of a VCommand. +// assert( doc ); + } + + /** Destroys the command */ + virtual ~VCommand() {} + + /** + * Executes the command. + * + * All the changes to the document are done here. + * All commands have to implement this function. + */ + virtual void execute() = 0; + + /** + * Unexecutes the command. + * + * All changes to the document have to be undone here. + */ + virtual void unexecute() {} + + /** + * Returns if the command changes the actual document selection. + * + * This flag is checked to determine if the document has to be redrawn. + * + * @return true if the selection is changed, else false + */ + virtual bool changesSelection() const { return false; } + + /** + * Returns the name of the command. + * + * @return the command name + */ + QString name() const + { + return m_name; + } + + /** + * Sets the name of the command. + * + * @param name the new command name + */ + void setName( const QString& name ) + { + m_name = name; + } + + /** + * Returns the icon of the command. + * + * @return the command icon + */ + QString icon() const + { + return m_icon; + } + + /** + * Returns the document the command works on. + * + * @return the command's document + */ + VDocument* document() const + { + return m_document; + } + +private: + VDocument* m_document; + + QString m_name; + QString m_icon; +}; + +/** + * Manages a set of commands. + * + * It keeps the commands in a list, commands higher in the list are older + * than lower commands. + * All commands in the list can be undone, beginning from the latest command + * at the end of the list. Undone commands can be redone, beginning at the + * oldest undone command. That makes it possible to go back and forth to a + * specific document state. + */ +class VCommandHistory : public QObject +{ + Q_OBJECT + +public: + /** + * Constructs a command history. + * + * @param part the part the commands are managed for + */ + VCommandHistory( KarbonPart* part ); + + /** Destroys the command history. */ + ~VCommandHistory(); + + /** + * Clears the command history by removing all commands. + * + * Emits the historyCleared signal + */ + void clear(); + + /** + * Adds a new command to the history. + * + * @param command the new command to add + * @param execute controls if the new command should be executed + */ + void addCommand( VCommand* command, bool execute = true ); + + + // limits + /** + * Returns the actual undo limit. + * + * @return the undo limit + */ + unsigned int undoLimit() const + { + return m_undoLimit; + } + + /** + * Sets a new undo limit. + * + * The undo limit controls how many commands are stored in the history. + * If the new limit is lower than the actual history size, the oldest + * commands are removed unitl the size matches the undo limit. + * + * @param limit the new undo limit + */ + void setUndoLimit( unsigned int limit ); + + /** + * Returns the actual redo limit. + * + * @return the redo limit + */ + unsigned int redoLimit() const + { + return m_redoLimit; + } + + /** + * Sets a new redo limit. + * + * The redo limit controls how many undone commands are stored in history. + * If the new limit is lower than the actual number of undone commands, + * the newest commands are removed until the number matches the redo limit. + * + * @param limit the new redo limit + */ + void setRedoLimit( unsigned int limit ); + + /** + * Read only access to the command history list. + * + * @return pointer to the list of commands + */ + const QPtrList<VCommand>* commands() const + { + return & m_commands; + } + +public slots: + /** Undoes the last command not already undone. */ + void undo(); + + /** Redoes the last command not already undone. */ + void redo(); + + /** + * Undoes the specified command. + * + * @param command the command to undo + */ + void undo( VCommand* command ); + + /** + * Redoes the specified command. + * + * @param command the command to redo + */ + void redo( VCommand* command ); + + /** + * Undoes all command up to the specified command. + * + * @param command the command up to which all later commands should be undone + */ + void undoAllTo( VCommand* command ); + + /** + * Redoes all command up to the specified command. + * + * @param command the command up to which all former commands should be redone + */ + void redoAllTo( VCommand* command ); + + /** + * Marks the actual document state as saved. + * + * The position within the list corresponding to the actual document state is saved. + */ + void documentSaved(); + +signals: + /** This signal is emitted when the command history gets cleared. */ + void historyCleared(); + + /** + * This signal is emitted when a command is executed. + * + * The executed command is given as the argument. + */ + void commandExecuted( VCommand* ); + + /** This signal is emitted when a command is executed. */ + void commandExecuted(); + + /** + * This signal is emitted when a command is added to the history. + * + * The added command is given as the argument. + */ + void commandAdded( VCommand* ); + + /** This signal is emitted when the first (oldest) command is removed. */ + void firstCommandRemoved(); + + /** This signal is emitted when the last (latest) command is removed. */ + void lastCommandRemoved(); + + /** + * This signal is emitted when the actual document state matches the last saved one. + * + * Use documentSaved to set the last saved document state. + */ + void documentRestored(); + +private: + // helpers + void clipCommands(); + void updateActions(); + + KarbonPart *m_part; + unsigned int m_undoLimit; + unsigned int m_redoLimit; + KAction *m_undo; + KAction *m_redo; + QPtrList<VCommand> m_commands; + int m_savedPos; +}; + +#endif + diff --git a/karbon/commands/vdeletecmd.cc b/karbon/commands/vdeletecmd.cc new file mode 100644 index 00000000..d94723c0 --- /dev/null +++ b/karbon/commands/vdeletecmd.cc @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vdeletecmd.h" +#include "vselection.h" +#include "vdocument.h" + +VDeleteCmd::VDeleteCmd( VDocument* doc ) + : VCommand( doc, i18n( "Delete Objects" ), "editdelete" ) +{ + m_selection = document()->selection()->clone(); + + if( m_selection->objects().count() == 1 ) + setName( i18n( "Delete Object" ) ); +} + +VDeleteCmd::VDeleteCmd( VDocument* doc, VObject* object ) + : VCommand( doc, i18n( "Delete Object" ), "editdelete" ) +{ + m_selection = new VSelection(); + m_selection->append( object ); +} + +VDeleteCmd::~VDeleteCmd() +{ + delete( m_selection ); +} + +void +VDeleteCmd::execute() +{ + document()->selection()->clear(); + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { + itr.current()->setState( VObject::deleted ); + } + + setSuccess( true ); +} + +void +VDeleteCmd::unexecute() +{ + document()->selection()->clear(); + + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { + itr.current()->setState( VObject::selected ); + document()->selection()->append( itr.current() ); + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vdeletecmd.h b/karbon/commands/vdeletecmd.h new file mode 100644 index 00000000..4e4b4333 --- /dev/null +++ b/karbon/commands/vdeletecmd.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VDELETECMD_H__ +#define __VDELETECMD_H__ + +#include "vcommand.h" + +class VSelection; + +/** + * A class to provide undo/redoable deletion of VObjects. + */ + +class VDeleteCmd : public VCommand +{ +public: + VDeleteCmd( VDocument *part ); + VDeleteCmd( VDocument *part, VObject *object ); + virtual ~VDeleteCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual bool changesSelection() const { return true; } + +protected: + VSelection *m_selection; +}; + +#endif + diff --git a/karbon/commands/vdeletenodescmd.cc b/karbon/commands/vdeletenodescmd.cc new file mode 100644 index 00000000..cde7d2a5 --- /dev/null +++ b/karbon/commands/vdeletenodescmd.cc @@ -0,0 +1,77 @@ +/* This file is doc of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <klocale.h> + +#include "vdeletenodescmd.h" +#include "vselection.h" +#include "vsegment.h" +#include "vpath.h" +#include "vdocument.h" + +VDeleteNodeCmd::VDeleteNodeCmd( VDocument *doc ) + : VCommand( doc, i18n( "Delete Node" ) ) +{ +} + +VDeleteNodeCmd::~VDeleteNodeCmd() +{ +} + +void +VDeleteNodeCmd::visitVSubpath( VSubpath& path ) +{ + VSegment* segment = path.first(); + + path.next(); // skip begin segment + while( segment ) + { + if( segment->state() != VSegment::deleted && segment->knotIsSelected() ) + { + segment->setState( VSegment::deleted ); + m_segments.append( segment ); + } + segment = segment->next(); + } + if( m_segments.count() > 0 ) + path.invalidateBoundingBox(); +} + +void +VDeleteNodeCmd::execute() +{ + VObjectListIterator itr( document()->selection()->objects() ); + + for( ; itr.current() ; ++itr ) + visit( *itr.current() ); + + setSuccess( m_segments.count() > 0 ); +} + +void +VDeleteNodeCmd::unexecute() +{ + QPtrListIterator<VSegment> itr( m_segments ); + for( ; itr.current() ; ++itr ) + itr.current()->setState( VSegment::normal ); + setSuccess( false ); +} + diff --git a/karbon/commands/vdeletenodescmd.h b/karbon/commands/vdeletenodescmd.h new file mode 100644 index 00000000..28e26226 --- /dev/null +++ b/karbon/commands/vdeletenodescmd.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VNODECMD_H__ +#define __VNODECMD_H__ + +#include "vcommand.h" +#include <koffice_export.h> + +class VSegment; +class VSubpath; + +class KARBONCOMMAND_EXPORT VDeleteNodeCmd : public VCommand +{ +public: + VDeleteNodeCmd( VDocument *doc ); + virtual ~VDeleteNodeCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual void visitVSubpath( VSubpath& path ); + +protected: + QPtrList<VSegment> m_segments; +}; + +#endif + diff --git a/karbon/commands/vdistributecmd.cc b/karbon/commands/vdistributecmd.cc new file mode 100644 index 00000000..d6ceb200 --- /dev/null +++ b/karbon/commands/vdistributecmd.cc @@ -0,0 +1,198 @@ +/* This file is doc of the KDE project + Copyright (C) 2005 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <klocale.h> + +#include "vdistributecmd.h" +#include "vtransformcmd.h" +#include "vdocument.h" +#include "vselection.h" + +VDistributeCmd::VDistributeCmd( VDocument *doc, Distribute distribute ) + : VCommand( doc, i18n( "Distribute Objects" ) ), m_distribute( distribute ) +{ + m_trafoCmds.setAutoDelete( true ); +} + +VDistributeCmd::~VDistributeCmd() +{ +} + +void +VDistributeCmd::execute() +{ + if( document()->selection()->objects().count() <= 2 ) + return; + + KoRect bbox; + double extent = 0.0; + double dx, dy; + + VObjectList objs = document()->selection()->objects(); + VObjectListIterator itr( objs ); + + QMap<double,VObject*> sortedPos; + + // sort by position and calculate sum of objects widht/height + for( ; itr.current(); ++itr ) + { + bbox = itr.current()->boundingBox(); + switch( m_distribute ) + { + case DISTRIBUTE_HORIZONTAL_CENTER: + sortedPos[bbox.center().x()] = itr.current(); + break; + case DISTRIBUTE_HORIZONTAL_GAP: + case DISTRIBUTE_HORIZONTAL_LEFT: + sortedPos[bbox.left()] = itr.current(); + extent += bbox.width(); + break; + case DISTRIBUTE_HORIZONTAL_RIGHT: + sortedPos[bbox.right()] = itr.current(); + break; + case DISTRIBUTE_VERTICAL_CENTER: + sortedPos[bbox.center().y()] = itr.current(); + break; + case DISTRIBUTE_VERTICAL_GAP: + case DISTRIBUTE_VERTICAL_BOTTOM: + sortedPos[bbox.bottom()] = itr.current(); + extent += bbox.height(); + break; + case DISTRIBUTE_VERTICAL_TOP: + sortedPos[bbox.top()] = itr.current(); + break; + } + } + + VObject* first = sortedPos.begin().data(); + VObject* last = (--sortedPos.end()).data(); + + // determine the available space to distribute + double space = getAvailableSpace( first, last, extent ); + double pos = 0.0, step = space / double(objs.count() - 1); + + VTranslateCmd *trafoCmd = 0L; + QMapIterator<double,VObject*> it = sortedPos.begin(), et = sortedPos.end(); + + for( ; it != et; ++it ) + { + if( it.data() == first || it.data() == last ) + continue; + + pos += step; + + document()->selection()->clear(); + + bbox = it.data()->boundingBox(); + + switch( m_distribute ) + { + case DISTRIBUTE_HORIZONTAL_CENTER: + dx = first->boundingBox().center().x() + pos - bbox.center().x(); + dy = 0.0; + break; + case DISTRIBUTE_HORIZONTAL_GAP: + dx = first->boundingBox().right() + pos + 0.5 * bbox.width() - bbox.center().x(); + dy = 0.0; + pos += bbox.width(); + break; + case DISTRIBUTE_HORIZONTAL_LEFT: + dx = first->boundingBox().left() + pos - bbox.left(); + dy = 0.0; + break; + case DISTRIBUTE_HORIZONTAL_RIGHT: + dx = first->boundingBox().right() + pos - bbox.right(); + dy = 0.0; + break; + case DISTRIBUTE_VERTICAL_CENTER: + dx = 0.0; + dy = first->boundingBox().center().y() + pos - bbox.center().y(); + break; + case DISTRIBUTE_VERTICAL_GAP: + dx = 0.0; + dy = first->boundingBox().bottom() + pos + 0.5 * bbox.height() - bbox.center().y(); + pos += bbox.height(); + break; + case DISTRIBUTE_VERTICAL_BOTTOM: + dx = 0.0; + dy = first->boundingBox().bottom() + pos - bbox.bottom(); + break; + case DISTRIBUTE_VERTICAL_TOP: + dx = 0.0; + dy = first->boundingBox().top() + pos - bbox.top(); + break; + }; + document()->selection()->append( it.data() ); + trafoCmd = new VTranslateCmd( document(), dx, dy ); + m_trafoCmds.append( trafoCmd ); + trafoCmd->execute(); + } + + // re-add object to selection + itr.toFirst(); + for( ; itr.current() ; ++itr ) + document()->selection()->append( itr.current() ); + setSuccess( true ); +} + +void +VDistributeCmd::unexecute() +{ + QPtrListIterator<VTranslateCmd> itr( m_trafoCmds ); + for( ; itr.current() ; ++itr ) + itr.current()->unexecute(); + setSuccess( false ); +} + +double +VDistributeCmd::getAvailableSpace( VObject *first, VObject *last, double extent ) +{ + switch( m_distribute ) + { + case DISTRIBUTE_HORIZONTAL_CENTER: + return last->boundingBox().center().x() - first->boundingBox().center().x(); + break; + case DISTRIBUTE_HORIZONTAL_GAP: + extent -= first->boundingBox().width() + last->boundingBox().width(); + return last->boundingBox().left() - first->boundingBox().right() - extent; + break; + case DISTRIBUTE_HORIZONTAL_LEFT: + return last->boundingBox().left() - first->boundingBox().left(); + break; + case DISTRIBUTE_HORIZONTAL_RIGHT: + return last->boundingBox().right() - first->boundingBox().right(); + break; + case DISTRIBUTE_VERTICAL_CENTER: + return last->boundingBox().center().y() - first->boundingBox().center().y(); + break; + case DISTRIBUTE_VERTICAL_GAP: + extent -= first->boundingBox().height() + last->boundingBox().height(); + return last->boundingBox().top() - first->boundingBox().bottom() - extent; + break; + case DISTRIBUTE_VERTICAL_BOTTOM: + return last->boundingBox().bottom() - first->boundingBox().bottom(); + break; + case DISTRIBUTE_VERTICAL_TOP: + return last->boundingBox().top() - first->boundingBox().top(); + break; + } + + return 0.0; +} diff --git a/karbon/commands/vdistributecmd.h b/karbon/commands/vdistributecmd.h new file mode 100644 index 00000000..2f0cffe3 --- /dev/null +++ b/karbon/commands/vdistributecmd.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright (C) 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VDISTRIBUTECMD_H__ +#define __VDISTRIBUTECMD_H__ + +#include "vcommand.h" + +class VTranslateCmd; + +/** A command for distributing objects */ + +class VDistributeCmd : public VCommand +{ +public: + enum Distribute + { + DISTRIBUTE_HORIZONTAL_CENTER, + DISTRIBUTE_HORIZONTAL_GAP, + DISTRIBUTE_HORIZONTAL_LEFT, + DISTRIBUTE_HORIZONTAL_RIGHT, + DISTRIBUTE_VERTICAL_CENTER, + DISTRIBUTE_VERTICAL_GAP, + DISTRIBUTE_VERTICAL_BOTTOM, + DISTRIBUTE_VERTICAL_TOP + }; + VDistributeCmd( VDocument *doc, Distribute distribute ); + virtual ~VDistributeCmd(); + + virtual void execute(); + virtual void unexecute(); + virtual bool changesSelection() const { return true; } + +protected: + double getAvailableSpace( VObject *first, VObject *last, double extent ); + + Distribute m_distribute; + QPtrList<VTranslateCmd> m_trafoCmds; +}; + +#endif + diff --git a/karbon/commands/vfillcmd.cc b/karbon/commands/vfillcmd.cc new file mode 100644 index 00000000..48572ade --- /dev/null +++ b/karbon/commands/vfillcmd.cc @@ -0,0 +1,123 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vfill.h" +#include "vfillcmd.h" +#include "vselection.h" +#include "vdocument.h" +#include "vcomposite.h" +#include "vgroup.h" +#include "vtext.h" + +VFillCmd::VFillCmd( VDocument *doc, const VFill &fill, const QString &icon ) + : VCommand( doc, i18n( "Fill Objects" ), icon ), m_fill( fill ) +{ + m_selection = document()->selection()->clone(); + + if( m_selection->objects().count() == 1 ) + setName( i18n( "Fill Object" ) ); +} + +VFillCmd::~VFillCmd() +{ + m_objects.clear(); + delete m_selection; + m_selection = 0L; +} + +void +VFillCmd::changeFill( const VFill &fill ) +{ + m_fill = fill; + + if( !m_selection ) + m_selection = document()->selection()->clone(); + + VObjectListIterator itr( m_selection->objects() ); + + for( ; itr.current() ; ++itr ) + { + visit( *itr.current() ); + } + + setSuccess( true ); +} + +void +VFillCmd::visitVGroup( VGroup& group ) +{ + VObjectListIterator itr( group.objects() ); + + for( ; itr.current() ; ++itr ) + { + m_oldfills.push_back( VFill( *( itr.current()->fill() ) ) ); + itr.current()->setFill( m_fill ); + m_objects.append(itr.current() ); + } +} + +void +VFillCmd::visitVPath( VPath& composite ) +{ + m_oldfills.push_back( VFill( *( composite.fill() ) ) ); + composite.setFill( m_fill ); + m_objects.append( &composite ); +} + +void +VFillCmd::visitVText( VText& text ) +{ + m_oldfills.push_back( VFill( *( text.fill() ) ) ); + text.setFill( m_fill ); + m_objects.append( &text ); +} + +void +VFillCmd::execute() +{ + if( !m_selection ) + m_selection = document()->selection()->clone(); + VObjectListIterator itr( m_selection->objects() ); + + for( ; itr.current() ; ++itr ) + { + visit( *itr.current() ); + } + + setSuccess( true ); +} + +void +VFillCmd::unexecute() +{ + VObjectListIterator itr( m_objects ); + + int i = 0; + + for( ; itr.current() ; ++itr ) + { + itr.current()->setFill( m_oldfills[ i++ ] ); + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vfillcmd.h b/karbon/commands/vfillcmd.h new file mode 100644 index 00000000..41661290 --- /dev/null +++ b/karbon/commands/vfillcmd.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VFILLCMD_H__ +#define __VFILLCMD_H__ + +#include "vcommand.h" +#include "vfill.h" +#include "vgroup.h" + +#include <qvaluevector.h> +#include <koffice_export.h> +class VSelection; + +// Fill object(s) + +class KARBONCOMMAND_EXPORT VFillCmd : public VCommand +{ +public: + VFillCmd( VDocument *doc, const VFill &, const QString& icon = "14_action" ); + virtual ~VFillCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual bool changesSelection() const { return true; } + + virtual void visitVGroup( VGroup& group ); + virtual void visitVPath( VPath& composite ); + virtual void visitVText( VText& text ); + + virtual void changeFill( const VFill & ); + virtual VSelection* getSelection() const { return m_selection; } + +protected: + VObjectList m_objects; + VSelection *m_selection; + + VFill m_fill; + + QValueVector<VFill> m_oldfills; +}; + +#endif + diff --git a/karbon/commands/vflattencmd.cc b/karbon/commands/vflattencmd.cc new file mode 100644 index 00000000..0cab021a --- /dev/null +++ b/karbon/commands/vflattencmd.cc @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vflattencmd.h" +#include <klocale.h> + +#include <core/vpath.h> +#include <core/vsegment.h> + +// TODO: Think about if we want to adapt this: + +/* + * <cite from GNU ghostscript's gxpflat.c> + * + * To calculate how many points to sample along a path in order to + * approximate it to the desired degree of flatness, we define + * dist((x,y)) = abs(x) + abs(y); + * then the number of points we need is + * N = 1 + sqrt(3/4 * D / flatness), + * where + * D = max(dist(p0 - 2*p1 + p2), dist(p1 - 2*p2 + p3)). + * Since we are going to use a power of 2 for the number of intervals, + * we can avoid the square root by letting + * N = 1 + 2^(ceiling(log2(3/4 * D / flatness) / 2)). + * (Reference: DEC Paris Research Laboratory report #1, May 1989.) + * + * We treat two cases specially. First, if the curve is very + * short, we halve the flatness, to avoid turning short shallow curves + * into short straight lines. Second, if the curve forms part of a + * character (indicated by flatness = 0), we let + * N = 1 + 2 * max(abs(x3-x0), abs(y3-y0)). + * This is probably too conservative, but it produces good results. + * + * </cite from GNU ghostscript's gxpflat.c> + */ + + +VFlattenCmd::VFlattenCmd( VDocument *doc, double flatness ) + : VReplacingCmd( doc, i18n( "Flatten Curves" ) ) +{ + m_flatness = flatness > 0.0 ? flatness : 1.0; +} + +void +VFlattenCmd::visitVSubpath( VSubpath& path ) +{ + path.first(); + + // Ommit first segment. + while( path.next() ) + { + while( !path.current()->isFlat( m_flatness ) ) + { + // Split at midpoint. + path.insert( + path.current()->splitAt( 0.5 ) ); + } + + // Convert to line. + path.current()->setDegree( 1 ); + + if( !success() ) + setSuccess(); + } +} + diff --git a/karbon/commands/vflattencmd.h b/karbon/commands/vflattencmd.h new file mode 100644 index 00000000..6e150ba3 --- /dev/null +++ b/karbon/commands/vflattencmd.h @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __FLATTENCMD_H__ +#define __FLATTENCMD_H__ + +#include <commands/vreplacingcmd.h> +#include <koffice_export.h> +class VSubpath; + +class KARBONCOMMAND_EXPORT VFlattenCmd : public VReplacingCmd +{ +public: + VFlattenCmd( VDocument *doc, double flatness ); + virtual ~VFlattenCmd() {} + + virtual void visitVSubpath( VSubpath& path ); + +protected: + double m_flatness; +}; + +#endif + diff --git a/karbon/commands/vgroupcmd.cc b/karbon/commands/vgroupcmd.cc new file mode 100644 index 00000000..bcad4d93 --- /dev/null +++ b/karbon/commands/vgroupcmd.cc @@ -0,0 +1,100 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vgroup.h" +#include "vgroupcmd.h" +#include "vselection.h" +#include "vdocument.h" +#include "vlayer.h" + +VGroupCmd::VGroupCmd( VDocument *doc ) + : VCommand( doc, i18n( "Group Objects" ), "14_group" ) +{ + m_selection = document()->selection()->clone(); + + m_group = 0L; +} + +VGroupCmd::~VGroupCmd() +{ + delete( m_selection ); +} + +void +VGroupCmd::execute() +{ + m_group = new VGroup( document()->activeLayer() ); + + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { + // remove from corresponding parent + VGroup *parent = dynamic_cast<VGroup*>( itr.current()->parent() ); + if( parent ) + parent->take( *itr.current() ); + + m_group->append( itr.current() ); + } + + document()->append( m_group ); + document()->selection()->clear(); + document()->selection()->append( m_group ); + + setSuccess( true ); +} + +void +VGroupCmd::unexecute() +{ + if( ! m_group ) + return; + + document()->selection()->clear(); + + VObjectListIterator itr( m_group->objects() ); + for ( ; itr.current() ; ++itr ) + { + // TODO : remove from corresponding VLayer + document()->selection()->append( itr.current() ); + } + + VGroup* parent; + if( ( parent = dynamic_cast<VGroup*>( m_group->parent() ) ) ) + { + // unregister from parent: + parent->take( *m_group ); + + // inform all objects in this group about their new parent + VObjectListIterator itr = m_selection->objects(); + + for ( ; itr.current() ; ++itr ) + { + parent->append( itr.current() ); + } + + m_group->clear(); + m_group->setState( VObject::deleted ); + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vgroupcmd.h b/karbon/commands/vgroupcmd.h new file mode 100644 index 00000000..4dad4028 --- /dev/null +++ b/karbon/commands/vgroupcmd.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGROUPCMD_H__ +#define __VGROUPCMD_H__ + +#include "vcommand.h" + + +class VSelection; + + +// Group object(s) + +class VGroup; + +class VGroupCmd : public VCommand +{ +public: + VGroupCmd( VDocument *doc ); + virtual ~VGroupCmd(); + + virtual void execute(); + virtual void unexecute(); + +protected: + VSelection* m_selection; + + VGroup* m_group; +}; + +#endif + diff --git a/karbon/commands/vinsertcmd.cc b/karbon/commands/vinsertcmd.cc new file mode 100644 index 00000000..2ec628c8 --- /dev/null +++ b/karbon/commands/vinsertcmd.cc @@ -0,0 +1,83 @@ +/* This file is part of the KDE project + Copyright (C) 2005, Inge Wallin + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <klocale.h> + +#include "vdocument.h" +#include "vlayer.h" +#include "vselection.h" +#include "vinsertcmd.h" +#include "vtransformcmd.h" + + +VInsertCmd::VInsertCmd( VDocument *doc, const QString& name, + VObjectList *objects, + double offset ) + : VCommand( doc, name, "14_insert" ), + m_objects( *objects ), + m_offset( offset ) +{ +} + +VInsertCmd::~VInsertCmd() +{ +} + + +void +VInsertCmd::execute() +{ + VObjectListIterator itr( m_objects ); + + document()->selection()->clear(); + for ( ; itr.current() ; ++itr ) { + VObject *object = itr.current(); + + if ( object->state() == VObject::deleted ) { + object->setState( VObject::normal ); + } + else { + document()->append( object ); + + if ( m_offset != 0.0 ) { + VTranslateCmd cmd( 0L, m_offset, -m_offset ); + cmd.visit( *object ); + } + } + + document()->selection()->append( object ); + } + + setSuccess( true ); +} + + +void +VInsertCmd::unexecute() +{ + document()->selection()->clear(); + + VObjectListIterator itr( m_objects ); + for ( ; itr.current() ; ++itr ) { + itr.current()->setState( VObject::deleted ); + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vinsertcmd.h b/karbon/commands/vinsertcmd.h new file mode 100644 index 00000000..7cc948a9 --- /dev/null +++ b/karbon/commands/vinsertcmd.h @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 2004, Inge Wallin + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VINSERTCMD_H__ +#define __VINSERTCMD_H__ + +#include "vcommand.h" +#include "vgroup.h" + + + + +// Insert object(s) + +class VInsert; + +class VInsertCmd : public VCommand +{ +public: + VInsertCmd( VDocument *doc, const QString& name, + VObjectList *objects, double offset ); + virtual ~VInsertCmd(); + + virtual void execute(); + virtual void unexecute(); + +protected: + VObjectList m_objects; + double m_offset; +}; + +#endif + diff --git a/karbon/commands/vlayercmd.cc b/karbon/commands/vlayercmd.cc new file mode 100644 index 00000000..d53155cd --- /dev/null +++ b/karbon/commands/vlayercmd.cc @@ -0,0 +1,86 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vlayer.h" +#include "vlayercmd.h" +#include "vdocument.h" + +VLayerCmd::VLayerCmd( VDocument* doc, const QString& name, VLayer* layer, VLayerCmdType order ) + : VCommand( doc, name, "14_layers" ), m_layer( layer ), m_cmdType( order ) +{ + if( order == addLayer ) + { + layer->setState( VObject::deleted ); + document()->insertLayer( layer ); + } + + m_oldState = layer->state(); +} + +void +VLayerCmd::execute() +{ + switch( m_cmdType ) + { + case addLayer: + m_layer->setState( VObject::normal ); + break; + + case deleteLayer: + m_layer->setState( VObject::deleted ); + break; + + case raiseLayer: + document()->raiseLayer( m_layer ); + break; + + case lowerLayer: + document()->lowerLayer( m_layer ); + break; + } + + setSuccess( true ); +} + +void +VLayerCmd::unexecute() +{ + switch ( m_cmdType ) + { + case addLayer: + m_layer->setState( VObject::deleted ); + break; + + case deleteLayer: + m_layer->setState( m_oldState ); + break; + + case raiseLayer: + document()->lowerLayer( m_layer ); + break; + + case lowerLayer: + document()->raiseLayer( m_layer ); + break; + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vlayercmd.h b/karbon/commands/vlayercmd.h new file mode 100644 index 00000000..b2771202 --- /dev/null +++ b/karbon/commands/vlayercmd.h @@ -0,0 +1,59 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VLAYERCMD_H__ +#define __VLAYERCMD_H__ + +#include "vcommand.h" +#include "vobject.h" + + +class VDocument; +class VLayer; + + +class VLayerCmd : public VCommand +{ +public: + /** + * The different types of layer commands. + */ + enum VLayerCmdType + { + addLayer, + raiseLayer, + lowerLayer, + deleteLayer + }; + + VLayerCmd( VDocument* doc, const QString& name, VLayer* layer, VLayerCmdType order ); + virtual ~VLayerCmd() {} + + virtual void execute(); + virtual void unexecute(); + +protected: + VLayer* m_layer; + VLayerCmdType m_cmdType; + VObject::VState m_oldState; +}; + +#endif + diff --git a/karbon/commands/vreplacingcmd.cc b/karbon/commands/vreplacingcmd.cc new file mode 100644 index 00000000..c14ffa1d --- /dev/null +++ b/karbon/commands/vreplacingcmd.cc @@ -0,0 +1,145 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vreplacingcmd.h" +#include "vselection.h" +#include "vdocument.h" + +VReplacingCmd::VReplacingCmd( VDocument* doc, const QString& name ) + : VCommand( doc, name ) +{ + // Set members. + m_oldObjects = doc ? document()->selection()->clone() : 0L; + m_newObjects = 0L; +} + +VReplacingCmd::~VReplacingCmd() +{ + delete( m_oldObjects ); + delete( m_newObjects ); +} + +void +VReplacingCmd::execute() +{ + // Did we have at least once a success? Otherwise we don't get inserted + // into the command history. + bool successful = false; + + + // Create new shapes if they don't exist yet. + if( !m_newObjects ) + { + m_newObjects = new VSelection(); + + // Pointer to temporary object. + VObject* newObject; + + VObjectListIterator itr( m_oldObjects->objects() ); + VObjectList rejects; + + for( ; itr.current(); ++itr ) + { + // Clone object and visit the clone. + newObject = itr.current()->clone(); + + // Success. + if( visit( *newObject ) ) + { + successful = true; + + // Insert new shape right before old shape. + itr.current()->parent()->insertInfrontOf( + newObject, itr.current() ); + + // Add new shape to list of new objects. + m_newObjects->append( newObject ); + } + // No success. + else + { + rejects.append( itr.current() ); + // Delete temporary object. + delete( newObject ); + } + } + VObjectListIterator jtr( rejects ); + for( ; jtr.current(); ++jtr ) + { + // Don't consider this object in the future anymore. + m_oldObjects->take( *jtr.current() ); + } + } + + // Nothing to do. + if( m_newObjects->objects().count() == 0 ) + return; + + + VObjectListIterator itr( m_oldObjects->objects() ); + + // Hide old objects. + for( ; itr.current(); ++itr ) + { + document()->selection()->take( *itr.current() ); + itr.current()->setState( VObject::deleted ); + } + + // Show new objects. + for( itr = m_newObjects->objects(); itr.current(); ++itr ) + { + itr.current()->setState( VObject::normal ); + document()->selection()->append( itr.current() ); + } + + + // Tell command history wether we had success at least once. + setSuccess( successful ); +} + +void +VReplacingCmd::unexecute() +{ + // Nothing to do. + if( m_newObjects->objects().count() == 0 ) + return; + + + VObjectListIterator itr( m_oldObjects->objects() ); + + // Show old objects. + for( ; itr.current(); ++itr ) + { + itr.current()->setState( VObject::normal ); + document()->selection()->append( itr.current() ); + } + + // Hide new objects. + for( itr = m_newObjects->objects(); itr.current(); ++itr ) + { + document()->selection()->take( *itr.current() ); + itr.current()->setState( VObject::deleted ); + } + + + // Reset success for command history. + setSuccess( false ); +} + diff --git a/karbon/commands/vreplacingcmd.h b/karbon/commands/vreplacingcmd.h new file mode 100644 index 00000000..54a14aac --- /dev/null +++ b/karbon/commands/vreplacingcmd.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VREPLACINGCMD_H__ +#define __VREPLACINGCMD_H__ + + +#include "vcommand.h" +#include <koffice_export.h> +class QString; +class VSelection; + + +/** + * VReplacingCmd is a generic command. Derive from it if you plan to do complex + * transformations upon selected objects which make it necessary to replace + * each object as a whole with a new object. + */ + +class KARBONCOMMAND_EXPORT VReplacingCmd : public VCommand +{ +public: + virtual void execute(); + virtual void unexecute(); + +protected: + /** + * Make it "abstract". + */ + VReplacingCmd( VDocument* doc, const QString& name ); + virtual ~VReplacingCmd(); + +private: + VSelection* m_oldObjects; + VSelection* m_newObjects; +}; + +#endif + diff --git a/karbon/commands/vshapecmd.cc b/karbon/commands/vshapecmd.cc new file mode 100644 index 00000000..59ea841a --- /dev/null +++ b/karbon/commands/vshapecmd.cc @@ -0,0 +1,71 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vcomposite.h" +#include "vdocument.h" +#include "vselection.h" +#include "vshapecmd.h" + + +VShapeCmd::VShapeCmd( VDocument* doc, const QString& name, VPath* shape, const QString& icon ) + : VCommand( doc, name, icon ), m_shape( shape ) +{ +} + +void +VShapeCmd::execute() +{ + if( !m_shape ) + return; + + if( m_shape->state() == VObject::deleted ) + { + document()->selection()->clear(); + m_shape->setState( VObject::normal ); + document()->selection()->append( m_shape ); + } + else + { + m_shape->setState( VObject::normal ); + m_shape->setFill( *( document()->selection()->fill() ) ); + m_shape->setStroke( *( document()->selection()->stroke() ) ); + + // Add path: + document()->append( m_shape ); + document()->selection()->clear(); + document()->selection()->append( m_shape ); + } + + setSuccess( true ); +} + +void +VShapeCmd::unexecute() +{ + if( !m_shape ) + return; + + document()->selection()->take( *m_shape ); + m_shape->setState( VObject::deleted ); + + setSuccess( false ); +} + diff --git a/karbon/commands/vshapecmd.h b/karbon/commands/vshapecmd.h new file mode 100644 index 00000000..dc033dbe --- /dev/null +++ b/karbon/commands/vshapecmd.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSHAPECMD_H__ +#define __VSHAPECMD_H__ + +#include "vcommand.h" +#include <koffice_export.h> +class VPath; + +/* + * Provides a common base class for creation commands since they all have + * a similar execute / unexecute behaviour and all build a VPath. Upon + * execution() the shape will be added to the document and selected, upon undoing + * it will be set to the deleted state. + */ +class KARBONCOMMAND_EXPORT VShapeCmd : public VCommand +{ +public: + VShapeCmd( VDocument* doc, const QString& name, VPath* shape, const QString& icon = "14_polygon" ); + virtual ~VShapeCmd() {} + + virtual void execute(); + virtual void unexecute(); + + virtual bool changesSelection() const { return true; } + +protected: + /// Pointer to the created shape. + VPath *m_shape; +}; + +#endif + diff --git a/karbon/commands/vstrokecmd.cc b/karbon/commands/vstrokecmd.cc new file mode 100644 index 00000000..26a9a1a7 --- /dev/null +++ b/karbon/commands/vstrokecmd.cc @@ -0,0 +1,193 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vselection.h" +#include "vstroke.h" +#include "vgradient.h" +#include "vstrokecmd.h" +#include "vdocument.h" + +VStrokeCmd::VStrokeCmd( VDocument *doc, const VStroke *stroke, const QString& icon ) + : VCommand( doc, i18n( "Stroke Objects" ), icon ), m_stroke( *stroke ) +{ + m_selection = document()->selection()->clone(); + m_state = Stroke; + + if( m_selection->objects().count() == 1 ) + setName( i18n( "Stroke Object" ) ); +} + +VStrokeCmd::VStrokeCmd( VDocument *doc, VGradient *gradient ) + : VCommand( doc, i18n( "Stroke Objects" ), "14_gradient" ) +{ + m_selection = document()->selection()->clone(); + m_state = Gradient; + m_stroke.gradient() = *gradient; + + if( m_selection->objects().count() == 1 ) + setName( i18n( "Stroke Object" ) ); +} + +VStrokeCmd::VStrokeCmd( VDocument *doc, VPattern *pattern ) + : VCommand( doc, i18n( "Stroke Objects" ), "14_pattern" ) +{ + m_selection = document()->selection()->clone(); + m_state = Pattern; + m_stroke.pattern() = *pattern; + + if( m_selection->objects().count() == 1 ) + setName( i18n( "Stroke Object" ) ); +} + +VStrokeCmd::VStrokeCmd( VDocument *doc, double width ) + : VCommand( doc, i18n( "Stroke Width" ), "linewidth" ) +{ + m_selection = document()->selection()->clone(); + m_state = LineWidth; + m_stroke.setLineWidth( width ); +} + +VStrokeCmd::VStrokeCmd( VDocument *doc, const VColor &color ) + : VCommand( doc, i18n( "Stroke Color" ), "linewidth" ) +{ + m_selection = document()->selection()->clone(); + m_state = Color; + m_stroke.setColor( color ); +} + +VStrokeCmd::VStrokeCmd( VDocument *doc, const QValueList<float>& array ) + : VCommand( doc, i18n( "Dash Pattern" ), "linewidth" ) +{ + m_selection = document()->selection()->clone(); + m_state = Dash; + m_stroke.dashPattern().setArray( array ); +} + +VStrokeCmd::~VStrokeCmd() +{ + delete( m_selection ); +} + +void +VStrokeCmd::changeStroke( const VColor &color ) +{ + m_state = Color; + m_stroke.setColor( color ); + + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { + //if( m_opacity == -1 ) + // m_color.setOpacity( itr.current()->stroke()->color().opacity() ); + + m_oldstrokes.push_back( *itr.current()->stroke() ); + + VStroke stroke( *itr.current()->stroke() ); + stroke.setParent( itr.current() ); + + stroke.setColor( m_stroke.color() ); + stroke.setType( VStroke::solid ); + + itr.current()->setStroke( stroke ); + } + + setSuccess( true ); +} + +void +VStrokeCmd::execute() +{ + VObjectListIterator itr( m_selection->objects() ); + for ( ; itr.current() ; ++itr ) + { + //if( m_opacity == -1 ) + // m_color.setOpacity( itr.current()->stroke()->color().opacity() ); + + m_oldstrokes.push_back( *itr.current()->stroke() ); + + VStroke stroke( *itr.current()->stroke() ); + stroke.setParent( itr.current() ); + if( m_state == LineWidth ) + stroke.setLineWidth( m_stroke.lineWidth() ); + else if( m_state == Color ) + { + stroke.setColor( m_stroke.color() ); + stroke.setType( VStroke::solid ); + } + else if( m_state == Gradient ) + { + stroke.gradient() = m_stroke.gradient(); + stroke.setType( VStroke::grad ); + } + else if( m_state == Pattern ) + { + stroke.pattern() = m_stroke.pattern(); + stroke.setType( VStroke::patt ); + } + else if( m_state == Stroke ) + { + stroke.setLineCap( m_stroke.lineCap() ); + stroke.setLineJoin( m_stroke.lineJoin() ); + stroke.setLineWidth( m_stroke.lineWidth() ); + if( m_stroke.type() == VStroke::none ) + { + stroke.setType( VStroke::none ); + } + else if( m_stroke.type() == VStroke::solid ) + { + stroke.setColor( m_stroke.color() ); + stroke.setType( VStroke::solid ); + } + else if( m_stroke.type() == VStroke::grad ) + { + stroke.gradient() = m_stroke.gradient(); + stroke.setType( VStroke::grad ); + } + else if( m_stroke.type() == VStroke::patt ) + { + stroke.pattern() = m_stroke.pattern(); + stroke.setType( VStroke::patt ); + } + } + else if( m_state == Dash ) + { + stroke.dashPattern() = m_stroke.dashPattern(); + } + itr.current()->setStroke( stroke ); + } + + setSuccess( true ); +} + +void +VStrokeCmd::unexecute() +{ + VObjectListIterator itr( m_selection->objects() ); + int i = 0; + for ( ; itr.current() ; ++itr ) + { + itr.current()->setStroke( m_oldstrokes[ i++ ] ); + } + + setSuccess( false ); +} + diff --git a/karbon/commands/vstrokecmd.h b/karbon/commands/vstrokecmd.h new file mode 100644 index 00000000..71adb334 --- /dev/null +++ b/karbon/commands/vstrokecmd.h @@ -0,0 +1,69 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTROKECMD_H__ +#define __VSTROKECMD_H__ + +#include "vcommand.h" +#include "vcolor.h" +#include "vstroke.h" + +#include <qvaluevector.h> +#include <koffice_export.h> +// Stroke object(s) + +class KARBONCOMMAND_EXPORT VStrokeCmd : public VCommand +{ +public: + VStrokeCmd( VDocument *doc, const VStroke *, const QString& icon = "14_action" ); + VStrokeCmd( VDocument *doc, VGradient * ); + VStrokeCmd( VDocument *doc, VPattern * ); + VStrokeCmd( VDocument *doc, const VColor & ); + VStrokeCmd( VDocument *doc, double ); + VStrokeCmd( VDocument *doc, const QValueList<float>& ); + virtual ~VStrokeCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual bool changesSelection() const { return true; } + + virtual void changeStroke( const VColor & ); + virtual VSelection* getSelection() const { return m_selection; } + +protected: + typedef enum + { + LineWidth, + Color, + Gradient, + Pattern, + Stroke, + Dash + } State; + + State m_state; + VSelection *m_selection; + VStroke m_stroke; + QValueVector<VStroke> m_oldstrokes; +}; + +#endif + diff --git a/karbon/commands/vtextcmd.cc b/karbon/commands/vtextcmd.cc new file mode 100644 index 00000000..5bab728d --- /dev/null +++ b/karbon/commands/vtextcmd.cc @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "karbon_view.h" + +#include "vpath.h" +#include "vtext.h" +#include "vtextcmd.h" + +VTextCmd::VTextCmd( KarbonPart* part, const QFont& font, const QString& text ) + : VShapeCmd( part, i18n( "Insert Text" ) ), m_font( font ), m_text( text ) +{ +} + +VObject* +VTextCmd::createPath() +{ + return + new VText( static_cast<KarbonView*>( m_part->views().getFirst() ), m_font, m_text ); +} + diff --git a/karbon/commands/vtextcmd.h b/karbon/commands/vtextcmd.h new file mode 100644 index 00000000..3e0f310e --- /dev/null +++ b/karbon/commands/vtextcmd.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTEXTCMD_H__ +#define __VTEXTCMD_H__ + +#include <qfont.h> + +#include "vshapecmd.h" + +// create a text-object. + +class VObject; + +class VTextCmd : public VShapeCmd +{ +public: + VTextCmd( KarbonPart* part, const QFont& font, const QString& m_text ); + virtual ~VTextCmd() {} + + virtual VObject* createPath(); + +protected: + QFont m_font; + QString m_text; +}; + +#endif + diff --git a/karbon/commands/vtransformcmd.cc b/karbon/commands/vtransformcmd.cc new file mode 100644 index 00000000..5feacac5 --- /dev/null +++ b/karbon/commands/vtransformcmd.cc @@ -0,0 +1,491 @@ +/* This file is doc of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <klocale.h> + +#include "vcomposite.h" +#include "vpath.h" +#include "vsegment.h" +#include "vselection.h" +#include "vtext.h" +#include "vimage.h" +#include "vtransformcmd.h" +#include "vstroke.h" +#include "vfill.h" +#include "vdocument.h" + +#include <kdebug.h> + +VTransformCmd::VTransformCmd( VDocument *doc, const QWMatrix& mat, bool duplicate ) + : VCommand( doc, i18n( "Transform Objects" ) ), m_mat( mat ), m_duplicate( duplicate ) +{ + m_selection = ( document() && document()->selection() ) + ? document()->selection()->clone() + : new VSelection(); + + if( m_duplicate ) + { + if( !m_selection || m_selection->objects().count() == 1 ) + setName( i18n( "Duplicate Object" ) ); + else + setName( i18n( "Duplicate Objects" ) ); + } + else if( !m_selection || m_selection->objects().count() == 1 ) + setName( i18n( "Transform Object" ) ); +} + +VTransformCmd::VTransformCmd( VDocument *doc, const QString& name, const QString& icon, bool duplicate ) + : VCommand( doc, name, icon ), m_duplicate( duplicate ) +{ + m_selection = ( document() && document()->selection() ) + ? document()->selection()->clone() + : new VSelection(); + + if( m_duplicate ) + { + if( !m_selection || m_selection->objects().count() == 1 ) + setName( i18n( "Duplicate Object" ) ); + else + setName( i18n( "Duplicate Objects" ) ); + } +} + +VTransformCmd::~VTransformCmd() +{ + delete( m_selection ); + m_selection = 0L; +} + +void +VTransformCmd::execute() +{ + VObjectListIterator itr( m_selection->objects() ); + + if( m_duplicate ) + { + // clone original objects, add duplicates to document, transform and select them + VObject *copy = 0L; + for( ; itr.current() ; ++itr ) + { + copy = itr.current()->clone(); + visit( *copy ); + document()->append( copy ); + document()->selection()->take( *itr.current() ); + document()->selection()->append( copy ); + m_duplicates.append( copy ); + } + } + else + { + // clear selection ... + document()->selection()->clear(); + // transform objects + for( ; itr.current() ; ++itr ) + { + visit( *itr.current() ); + } + // ... and re-add all objects incase we are re-executing the command + document()->selection()->append( m_selection->objects() ); + } + + setSuccess( true ); +} + +void +VTransformCmd::unexecute() +{ + // inverting the matrix should undo the affine transformation + m_mat = m_mat.invert(); + + if( m_duplicate ) + { + // remove duplicated objects + VObjectListIterator itr( m_duplicates ); + for( ; itr.current() ; ++itr ) + { + document()->selection()->take( *itr.current() ); + itr.current()->setState( VObject::deleted ); + } + VObjectListIterator jtr( m_selection->objects() ); + + // add original selection objects to new selection + for( ; jtr.current() ; ++jtr ) + { + document()->selection()->append( jtr.current() ); + } + } + else + { + document()->selection()->clear(); + // move objects back to original position + visit( *m_selection ); + document()->selection()->append( m_selection->objects() ); + } + // reset + m_mat = m_mat.invert(); + setSuccess( false ); +} + +void +VTransformCmd::visitVObject( VObject& object ) +{ + // Apply transformation to gradients. + VStroke* stroke = object.stroke(); + if( stroke && stroke->type() == VStroke::grad ) + stroke->gradient().transform( m_mat ); + else if( stroke && stroke->type() == VStroke::patt ) + stroke->pattern().transform( m_mat ); + + VFill* fill = object.fill(); + if( fill && fill->type() == VFill::grad ) + fill->gradient().transform( m_mat ); + else if( fill && fill->type() == VFill::patt ) + fill->pattern().transform( m_mat ); +} + +void +VTransformCmd::visitVPath( VPath& composite ) +{ + if( composite.state() == VObject::hidden || + composite.state() == VObject::normal_locked || + composite.state() == VObject::hidden_locked ) + return; + + visitVObject( composite ); + + composite.transform( m_mat ); + + VVisitor::visitVPath( composite ); +} + +void +VTransformCmd::visitVSubpath( VSubpath& path ) +{ + if( path.state() == VObject::hidden || + path.state() == VObject::normal_locked || + path.state() == VObject::hidden_locked ) + return; + + VSegment* segment = path.first(); + + while( segment ) + { + for( unsigned short i = 0; i < segment->degree(); ++i ) + { + segment->setPoint( i, segment->point( i ).transform( m_mat ) ); + } + + segment = segment->next(); + } + + path.invalidateBoundingBox(); +} + +void +VTransformCmd::visitVText( VText& text ) +{ + if( text.state() == VObject::hidden || + text.state() == VObject::normal_locked || + text.state() == VObject::hidden_locked ) + return; + + visitVObject( text ); + + visit( text.basePath() ); + + VPathListIterator itr( text.glyphs() ); + + for( ; itr.current() ; ++itr ) + { + visit( *itr.current() ); + } + + text.invalidateBoundingBox(); +} + +void +VTransformCmd::visitVImage( VImage &img ) +{ + if( img.state() == VObject::hidden || + img.state() == VObject::normal_locked || + img.state() == VObject::hidden_locked ) + return; + + img.transform( m_mat ); +} + +VTranslateCmd::VTranslateCmd( VDocument *doc, double d1, double d2, bool duplicate ) + : VTransformCmd( doc, i18n( "Translate Objects" ), "translate", duplicate ) +{ + if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) ) + setName( i18n( "Translate Object" ) ); + + m_mat.translate( d1, d2 ); +} + + +VScaleCmd::VScaleCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate ) + : VTransformCmd( doc, i18n( "Scale Objects" ), "14_select", duplicate ) +{ + if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) ) + setName( i18n( "Scale Object" ) ); + + m_mat.translate( p.x(), p.y() ); + m_mat.scale( s1, s2 ); + m_mat.translate( -p.x(), -p.y() ); +} + + +VShearCmd::VShearCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate ) + : VTransformCmd( doc, i18n( "Shear Objects" ), "14_shear", duplicate ) +{ + if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) ) + setName( i18n( "Shear Object" ) ); + + m_mat.translate( p.x(), p.y() ); + m_mat.shear( s1, s2 ); + m_mat.translate( -p.x(), -p.y() ); +} + +VRotateCmd::VRotateCmd( VDocument *doc, const KoPoint& p, double angle, bool duplicate ) + : VTransformCmd( doc, i18n( "Rotate Objects" ), "14_rotate", duplicate ) +{ + if( !duplicate && ( !m_selection || m_selection->objects().count() == 1 ) ) + setName( i18n( "Rotate Object" ) ); + + m_mat.translate( p.x(), p.y() ); + m_mat.rotate( angle ); + m_mat.translate( -p.x(), -p.y() ); +} + +VTranslateBezierCmd::VTranslateBezierCmd( VDocument *doc, VSegment *segment, double d1, double d2, bool firstControl ) + : VCommand( doc, i18n( "Translate Bezier" ) ), m_segment( segment ), m_firstControl( firstControl ) + , m_subpath(0L) +{ + m_mat.translate( d1, d2 ); + m_segmenttwo = 0L; + + if( document() && document()->selection() ) + { + VObjectListIterator itr( document()->selection()->objects() ); + + // find subpath containing the segment + for( ; itr.current() ; ++itr ) + visit( *itr.current() ); + } +} + +VTranslateBezierCmd::~VTranslateBezierCmd() +{ +} + +void +VTranslateBezierCmd::execute() +{ + if( m_segment->degree() == 3 ) + { + QWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() ); + if( m_firstControl ) + { + if( m_segment->prev() && + m_segment->prev()->degree() == 3 && + m_segment->prev()->isSmooth() ) + { + m_segmenttwo = m_segment->prev(); + for( uint i = 0;i < m_segmenttwo->degree();i++ ) + { + m_segmenttwo->selectPoint( i, i == 1 ); + + if( i == 1 ) + m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) ); + } + } + } + else + { + m_segmenttwo = ( m_segment->isSmooth() && m_segment->next()->degree() == 3 ) ? m_segment->next() : 0L; + if( m_segmenttwo ) + { + for( uint i = 0;i < m_segmenttwo->degree();i++ ) + { + m_segmenttwo->selectPoint( i, i == 0 ); + + if( i == 0 ) + m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2 ) ); + } + } + } + + for( uint i = 0;i < m_segment->degree();i++ ) + { + m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) ); + + if( i == uint( m_firstControl ? 0 : 1 ) ) + m_segment->setPoint( i, m_segment->point( i ).transform( m_mat ) ); + } + } + + if( m_subpath ) + m_subpath->invalidateBoundingBox(); + + setSuccess( true ); +} + +void +VTranslateBezierCmd::unexecute() +{ + QWMatrix m2( m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), -m_mat.dx(), -m_mat.dy() ); + if( m_segment ) + { + for( uint i = 0;i < m_segment->degree();i++ ) + { + m_segment->selectPoint( i, i == uint( m_firstControl ? 0 : 1 ) ); + + if( i == uint( m_firstControl ? 0 : 1 ) ) + m_segment->setPoint( i, m_segment->point( i ).transform( m_mat.invert() ) ); + } + + if( m_segmenttwo ) + { + uint index = m_firstControl ? 1 : 0; + for( uint i = 0;i < m_segmenttwo->degree();i++ ) + { + m_segmenttwo->selectPoint( i, i == index ); + + if( i == index ) + m_segmenttwo->setPoint( i, m_segmenttwo->point( i ).transform( m2.invert() ) ); + } + } + } + setSuccess( false ); +} + +void +VTranslateBezierCmd::visitVSubpath( VSubpath& path ) +{ + if( m_subpath ) + return; + + VSegment* segment = path.first(); + + // check all segments of the path + while( segment ) + { + if( segment == m_segment ) + { + m_subpath = &path; + break; + } + segment = segment->next(); + } +} + +VTranslatePointCmd::VTranslatePointCmd( VDocument *doc, double d1, double d2 ) + : VCommand( doc, i18n( "Translate Points" ), "translate" ) +{ + m_mat.translate( d1, d2 ); + + if( document() && document()->selection() ) + { + VObjectListIterator itr( document()->selection()->objects() ); + + // collect all points to translate + for( ; itr.current() ; ++itr ) + visit( *itr.current() ); + + if( m_segPnts.size() > 1 || ( m_segPnts.size() == 0 && m_segPnts.begin().data().size() > 1 ) ) + setName( i18n( "Translate Point" ) ); + } +} + +VTranslatePointCmd::~VTranslatePointCmd() +{ +} + +void +VTranslatePointCmd::execute() +{ + translatePoints(); + setSuccess( true ); +} + +void +VTranslatePointCmd::unexecute() +{ + m_mat = m_mat.invert(); + translatePoints(); + m_mat = m_mat.invert(); + setSuccess( false ); +} + +void +VTranslatePointCmd::visitVSubpath( VSubpath& path ) +{ + if( path.state() == VObject::hidden || + path.state() == VObject::normal_locked || + path.state() == VObject::hidden_locked ) + return; + + VSegment* segment = path.first(); + + uint segCnt = m_segPnts.size(); + + // save indices of selected points for all segments + while( segment ) + { + QValueVector<int> pnts; + + for( unsigned short i = 0; i < segment->degree(); ++i ) + { + if( segment->pointIsSelected( i ) ) + pnts.push_back( i ); + } + if( pnts.size() ) + m_segPnts[segment] = pnts; + + segment = segment->next(); + } + + // save subpaths which have selected points + if( segCnt != m_segPnts.size() ) + m_subpaths.append( &path ); +} + +void +VTranslatePointCmd::translatePoints() +{ + QMap<VSegment*, QValueVector<int> >::iterator it, et = m_segPnts.end(); + + // iterate over the segments and transform all selected points + for( it = m_segPnts.begin(); it != et; ++it ) + { + VSegment *segment = it.key(); + QValueVector<int> &pnts = it.data(); + + int pntCnt = pnts.size(); + for( int i = 0; i < pntCnt; ++i ) + segment->setPoint( pnts[i], segment->point( pnts[i] ).transform( m_mat ) ); + } + + // invalidate all changed subpaths + VObjectListIterator itr( m_subpaths ); + for( ; itr.current(); ++itr ) + itr.current()->invalidateBoundingBox(); +} diff --git a/karbon/commands/vtransformcmd.h b/karbon/commands/vtransformcmd.h new file mode 100644 index 00000000..daa26950 --- /dev/null +++ b/karbon/commands/vtransformcmd.h @@ -0,0 +1,136 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTRANSFORMCMD_H__ +#define __VTRANSFORMCMD_H__ + +#include <qvaluevector.h> +#include "vcommand.h" +#include "vgroup.h" +#include <koffice_export.h> +// Transform object(s) with a specified matrix and allow undo. + + +class QWMatrix; +class VPath; +class VSubpath; +class VSegment; +class VSelection; + + +class KARBONCOMMAND_EXPORT VTransformCmd : public VCommand +{ +public: + VTransformCmd( VDocument *doc, const QWMatrix& mat, bool duplicate = false ); + virtual ~VTransformCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual void visitVPath( VPath& composite ); + virtual void visitVSubpath( VSubpath& path ); + virtual void visitVText( VText& text ); + virtual void visitVImage( VImage& img ); + virtual void visitVObject( VObject& object ); + + void setMatrix( const QWMatrix& m ) + { + m_mat = m; + } + +protected: + VTransformCmd( VDocument *doc, const QString& name, const QString& icon, bool duplicate = false ); + + VSelection* m_selection; + VObjectList m_duplicates; + + QWMatrix m_mat; + + bool m_duplicate; +}; + + +class KARBONCOMMAND_EXPORT VTranslateCmd : public VTransformCmd +{ +public: + VTranslateCmd( VDocument *doc, double d1, double d2, bool duplicate = false ); +}; + + +class KARBONCOMMAND_EXPORT VScaleCmd : public VTransformCmd +{ +public: + VScaleCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate = false ); +}; + + +class KARBONCOMMAND_EXPORT VShearCmd : public VTransformCmd +{ +public: + VShearCmd( VDocument *doc, const KoPoint& p, double s1, double s2, bool duplicate = false ); +}; + + +class KARBONCOMMAND_EXPORT VRotateCmd : public VTransformCmd +{ +public: + VRotateCmd( VDocument *doc, const KoPoint& p, double angle, bool duplicate = false ); +}; + +class KARBONCOMMAND_EXPORT VTranslateBezierCmd : public VCommand +{ +public: + VTranslateBezierCmd( VDocument *doc, VSegment *segment, double d1, double d2, bool firstControl ); + virtual ~VTranslateBezierCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual void visitVSubpath( VSubpath& path ); + +protected: + QWMatrix m_mat; + VSegment *m_segment; + VSegment *m_segmenttwo; + bool m_firstControl; + VSubpath *m_subpath; +}; + +class KARBONCOMMAND_EXPORT VTranslatePointCmd : public VCommand +{ +public: + VTranslatePointCmd( VDocument *doc, double d1, double d2 ); + virtual ~VTranslatePointCmd(); + + virtual void execute(); + virtual void unexecute(); + + virtual void visitVSubpath( VSubpath& path ); + +protected: + void translatePoints(); + + QWMatrix m_mat; + QMap<VSegment*, QValueVector<int> > m_segPnts; + VObjectList m_subpaths; +}; + +#endif + diff --git a/karbon/commands/vungroupcmd.cc b/karbon/commands/vungroupcmd.cc new file mode 100644 index 00000000..314a873e --- /dev/null +++ b/karbon/commands/vungroupcmd.cc @@ -0,0 +1,99 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vgroup.h" +#include "vungroupcmd.h" +#include "vselection.h" +#include "vdocument.h" +#include "vlayer.h" + +VUnGroupCmd::VUnGroupCmd( VDocument *doc ) + : VCommand( doc, i18n( "Ungroup Objects" ), "14_ungroup" ) +{ + m_group = dynamic_cast<VGroup *>( document()->selection()->objects().getFirst() ); + if( m_group ) + m_objects = m_group->objects(); +} + +VUnGroupCmd::~VUnGroupCmd() +{ +} + +void +VUnGroupCmd::execute() +{ + if( !m_group ) + return; + + document()->selection()->clear(); + + VObjectListIterator itr( m_group->objects() ); + for ( ; itr.current() ; ++itr ) + { + // TODO : remove from corresponding VLayer + document()->selection()->append( itr.current() ); + } + + VGroup* parent; + if( ( parent = dynamic_cast<VGroup*>( m_group->parent() ) ) ) + { + // unregister from parent: + parent->take( *m_group ); + + // inform all objects in this group about their new parent + VObjectListIterator itr = m_group->objects(); + + for ( ; itr.current() ; ++itr ) + { + itr.current()->invalidateBoundingBox(); + parent->append( itr.current() ); + } + + m_group->clear(); + m_group->setState( VObject::deleted ); + } + + setSuccess( true ); +} + +void +VUnGroupCmd::unexecute() +{ + if( !m_group ) + return; + + VObjectListIterator itr( m_objects ); + for ( ; itr.current() ; ++itr ) + { + // TODO : remove from corresponding VLayer + document()->activeLayer()->take( *itr.current() ); + m_group->append( itr.current() ); + } + + m_group->setState( VObject::normal ); + document()->append( m_group ); + document()->selection()->clear(); + document()->selection()->append( m_group ); + + setSuccess( false ); +} + diff --git a/karbon/commands/vungroupcmd.h b/karbon/commands/vungroupcmd.h new file mode 100644 index 00000000..5fb5a40c --- /dev/null +++ b/karbon/commands/vungroupcmd.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VUNGROUPCMD_H__ +#define __VUNGROUPCMD_H__ + +#include "vcommand.h" + +// Group object(s) + +class VGroup; + +class VUnGroupCmd : public VCommand +{ +public: + VUnGroupCmd( VDocument *doc ); + virtual ~VUnGroupCmd(); + + virtual void execute(); + virtual void unexecute(); + +protected: + VObjectList m_objects; + + VGroup* m_group; +}; + +#endif + diff --git a/karbon/commands/vzordercmd.cc b/karbon/commands/vzordercmd.cc new file mode 100644 index 00000000..2839120f --- /dev/null +++ b/karbon/commands/vzordercmd.cc @@ -0,0 +1,172 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vzordercmd.h" +#include "vselection.h" +#include "vdocument.h" +#include "vlayer.h" + +VZOrderCmd::VZOrderCmd( VDocument *doc, VOrder state ) + : VCommand( doc, i18n( "Order Selection" ) ), m_state( state ) +{ + m_selection = document()->selection()->clone(); +} + +VZOrderCmd::VZOrderCmd( VDocument *doc, VObject *obj, VOrder state ) + : VCommand( doc, i18n( "Order Selection" ) ), m_state( state ) +{ + m_selection = new VSelection(); + m_selection->append( obj ); +} + +VZOrderCmd::~VZOrderCmd() +{ + delete( m_selection ); +} + +void +VZOrderCmd::execute() +{ + if( m_state == sendToBack ) + { + VObjectListIterator itr( document()->selection()->objects() ); + for ( itr.toLast() ; itr.current() ; --itr ) + { + // remove from old layer + VObjectList objects; + VLayerListIterator litr( document()->layers() ); + + for ( ; litr.current(); ++litr ) + { + objects = litr.current()->objects(); + VObjectListIterator itr2( objects ); + for ( ; itr2.current(); ++itr2 ) + if( itr2.current() == itr.current() ) + { + litr.current()->sendToBack( *itr2.current() ); + itr2.current()->setState( VObject::selected ); + } + } + } + } + else if( m_state == bringToFront ) + { + VObjectListIterator itr( document()->selection()->objects() ); + for ( ; itr.current() ; ++itr ) + { + // remove from old layer + VObjectList objects; + VLayerListIterator litr( document()->layers() ); + + for ( ; litr.current(); ++litr ) + { + objects = litr.current()->objects(); + VObjectListIterator itr2( objects ); + for ( ; itr2.current(); ++itr2 ) + if( itr2.current() == itr.current() ) + { + litr.current()->bringToFront( *itr2.current() ); + itr2.current()->setState( VObject::selected ); + } + } + } + } + else if( m_state == up || m_state == down ) + { + VSelection selection = *m_selection; + // TODO : this doesn't work for objects inside groups! + VLayerListIterator litr( document()->layers() ); + while( !selection.objects().isEmpty() && litr.current() ) + { + for ( ; litr.current(); ++litr ) + { + if( litr.current()->state() == VObject::deleted ) + continue; + VObjectList objects = litr.current()->objects(); + VObjectList todo; + VObjectListIterator objectItr( objects ); + // find all selected VObjects that are in the current layer + for ( ; objectItr.current(); ++objectItr ) + { + VObjectListIterator selectionItr( selection.objects() ); + for ( ; selectionItr.current() ; ++selectionItr ) + { + if( objectItr.current() == selectionItr.current() ) + { + if( m_state == up ) + todo.prepend( objectItr.current() ); + else + todo.append( objectItr.current() ); + } + } + } + + kdDebug(38000) << "todo.count() : " << todo.count() << endl; + + // we have found the affected vobjects in this vlayer + VObjectListIterator todoItr( todo ); + for ( ; todoItr.current(); ++todoItr ) + { + if( m_state == up ) + litr.current()->upwards( *todoItr.current() ); + else + litr.current()->downwards( *todoItr.current() ); + // remove from selection + selection.take( *todoItr.current() ); + // make sure object stays selected + todoItr.current()->setState( VObject::selected ); + } + } + } + } + setSuccess( true ); +} + +void +VZOrderCmd::unexecute() +{ + if( m_state == sendToBack ) + { + m_state = bringToFront; + execute(); + m_state = sendToBack; + } + else if( m_state == bringToFront ) + { + m_state = sendToBack; + execute(); + m_state = bringToFront; + } + else if( m_state == up ) + { + m_state = down; + execute(); + m_state = up; + } + else if( m_state == down ) + { + m_state = up; + execute(); + m_state = down; + } + setSuccess( false ); +} + diff --git a/karbon/commands/vzordercmd.h b/karbon/commands/vzordercmd.h new file mode 100644 index 00000000..b2ca9a94 --- /dev/null +++ b/karbon/commands/vzordercmd.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VZORDERCMD_H__ +#define __VZORDERCMD_H__ + +#include "vcommand.h" + +class VSelection; + +/** + * Command that changes the z-order of the selection within a layer + * to front, back, one step up, or one step down. + */ +class VZOrderCmd : public VCommand +{ +public: + enum VOrder + { + bringToFront = 0, + up = 1, + down = 2, + sendToBack = 3 + }; + + VZOrderCmd( VDocument* doc, VOrder ); + VZOrderCmd( VDocument* doc, VObject *obj, VOrder ); + virtual ~VZOrderCmd(); + + virtual void execute(); + virtual void unexecute(); + virtual bool isExecuted() { return true; } + +protected: + VSelection *m_selection; + VOrder m_state; +}; + +#endif + diff --git a/karbon/configure.in.bot b/karbon/configure.in.bot new file mode 100644 index 00000000..18656f01 --- /dev/null +++ b/karbon/configure.in.bot @@ -0,0 +1,24 @@ +if test -z "$LIBART_LIBS"; then + echo "" + echo "You're missing libart 2.3.8. karbon will not be compiled." + echo "You can download libart from" + echo "http://svg.kde.org/download.html" + echo "" + all_tests=bad +else + if test -z "$LIBFONTCONFIG_LIBS"; then + echo "" + echo "You're missing fontconfig 1.0.1 or newer. karbon will not have text support." + echo "You can download fontconfig from http://fontconfig.org/" + echo "" + all_tests=bad + fi + + if test -z "$LIBFREETYPE_LIBS"; then + echo "" + echo "You're missing libfreetype 5.0 or newer. karbon will not have text support." + echo "You can download libfreetype from http://www.freetype.org/" + echo "" + all_tests=bad + fi +fi diff --git a/karbon/configure.in.in b/karbon/configure.in.in new file mode 100644 index 00000000..03258f0b --- /dev/null +++ b/karbon/configure.in.in @@ -0,0 +1,119 @@ + +KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ + AC_MSG_WARN([Could not find libfreetype anywhere, check http://www.freetype.org/]) +]) + +if test -n "$FREETYPE_CONFIG"; then + vers=`$FREETYPE_CONFIG --version 2>/dev/null | $SED -e 's/libfreetype //' | $AWK 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 5000000 + then + LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`" + LIBFREETYPE_RPATH= + for args in $LIBFREETYPE_LIBS; do + case $args in + -L*) + LIBFREETYPE_RPATH="$LIBFREETYPE_RPATH $args" + ;; + esac + done + LIBFREETYPE_RPATH=`echo $LIBFREETYPE_RPATH | $SED -e "s/-L/-R/g"` + LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`" + else + AC_MSG_WARN([You need at least libfreetype 5.0]) + fi +fi + +AC_SUBST(LIBFREETYPE_LIBS) +AC_SUBST(LIBFREETYPE_CFLAGS) +AC_SUBST(LIBFREETYPE_RPATH) + + +KDE_FIND_PATH(libart2-config, LIBART_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ + AC_MSG_WARN([Could not find libart anywhere, check http://www.levien.com/libart/]) +]) + +if test -n "$LIBART_CONFIG"; then + vers=`$LIBART_CONFIG --version 2>/dev/null | $AWK 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 2003008 + then + LIBART_LIBS="`$LIBART_CONFIG --libs`" + LIBART_RPATH= + for args in $LIBART_LIBS; do + case $args in + -L*) + LIBART_RPATH="$LIBART_RPATH $args" + ;; + esac + done + LIBART_RPATH=`echo $LIBART_RPATH | $SED -e "s/-L/-R/g"` + LIBART_CFLAGS="`$LIBART_CONFIG --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_LIBART, 1, [Defines if your system has the libart library]) + else + AC_MSG_WARN([You need at least libart 2.3.8]) + fi +fi + +AC_SUBST(LIBART_LIBS) +AC_SUBST(LIBART_CFLAGS) +AC_SUBST(LIBART_RPATH) + + +# Check for fontconfig +KDE_FIND_PATH(fontconfig-config, FONTCONFIG_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/bin /usr/local/bin /opt/local/bin], [ + KDE_FIND_PATH(pkg-config, PKGCONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/bin /usr/local/bin /opt/local/bin], [ + AC_MSG_WARN([Could not find neither pkg-config nor fontconfig-config, check http://www.fontconfig.org/ ]) + ]) +]) + +if test -n "$PKGCONFIG"; then + vers=`$PKGCONFIG fontconfig --modversion 2>/dev/null | $SED -e 's/libfontconfig //' | $AWK 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 1000001 + then + LIBFONTCONFIG_LIBS="`$PKGCONFIG fontconfig --libs`" + LIBFONTCONFIG_RPATH= + for args in $LIBFONTCONFIG_LIBS; do + case $args in + -L*) + LIBFONTCONFIG_RPATH="$LIBFONTCONFIG_RPATH $args" + ;; + esac + done + LIBFONTCONFIG_RPATH=`echo $LIBFONTCONFIG_RPATH | $SED -e "s/-L/-R/g"` + LIBFONTCONFIG_CFLAGS="`$PKGCONFIG fontconfig --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_FONTCONFIG, 1, [Defines if your system has the libfontconfig library]) + fi +fi + +if test -n "$FONTCONFIG_CONFIG"; then + vers=`$FONTCONFIG_CONFIG --version 2>/dev/null | $SED -e 's/libfontconfig //' | $AWK 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'` + if test -n "$vers" && test "$vers" -ge 1000001 + then + LIBFONTCONFIG_LIBS="`$FONTCONFIG_CONFIG --libs`" + LIBFONTCONFIG_RPATH= + for args in $LIBFONTCONFIG_LIBS; do + case $args in + -L*) + LIBFONTCONFIG_RPATH="$LIBFONTCONFIG_RPATH $args" + ;; + esac + done + LIBFONTCONFIG_RPATH=`echo $LIBFONTCONFIG_RPATH | $SED -e "s/-L/-R/g"` + LIBFONTCONFIG_CFLAGS="`$FONTCONFIG_CONFIG --cflags`" + + AC_DEFINE_UNQUOTED(HAVE_FONTCONFIG, 1, [Defines if your system has the libfontconfig library]) + fi +fi + +AC_SUBST(LIBFONTCONFIG_LIBS) +AC_SUBST(LIBFONTCONFIG_CFLAGS) +AC_SUBST(LIBFONTCONFIG_RPATH) + +if test -z "$LIBART_LIBS"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE karbon" +fi + +if test -n "$LIBFREETYPE_LIBS" -a -n "$LIBFONTCONFIG_LIBS"; then + AC_DEFINE_UNQUOTED(HAVE_KARBONTEXT, 1, [Defines if your system has the fontconfig and freetype libraries]) +fi diff --git a/karbon/core/Makefile.am b/karbon/core/Makefile.am new file mode 100644 index 00000000..aabebf80 --- /dev/null +++ b/karbon/core/Makefile.am @@ -0,0 +1,73 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../render \ + -I$(srcdir)/../visitors \ + $(LIBFREETYPE_CFLAGS) $(LIBFONTCONFIG_CFLAGS) $(all_includes) + +noinst_LTLIBRARIES = libkarboncore.la + +noinst_HEADERS = \ + vcolor.h \ + vcomposite.h \ + vcomposite_iface.h \ + vdashpattern.h \ + vdocument.h \ + vfill.h \ + vglobal.h \ + vgradient.h \ + vgroup.h \ + vobject_iface.h \ + vgroup_iface.h \ + vimage.h \ + vkarbonplugin.h \ + vlayer.h \ + vobject.h \ + vpath.h \ + vpattern.h \ + vsegment.h \ + vselection.h \ + vstroke.h \ + vvisitor.h \ + vlayer_iface.h \ + vtext.h \ + vtext_iface.h \ + vclipgroup.h \ + vcursor.h + +libkarboncore_la_SOURCES = \ + vcolor.cc \ + vcomposite.cc \ + vcomposite_iface.cc \ + vcomposite_iface.skel \ + vdashpattern.cc \ + vdocument.cc \ + vfill.cc \ + vglobal.cc \ + vgradient.cc \ + vgroup.cc \ + vobject_iface.cc \ + vobject_iface.skel \ + vgroup_iface.cc \ + vgroup_iface.skel \ + vimage.cc \ + vkarbonplugin.cc \ + vlayer.cc \ + vobject.cc \ + vpath.cc \ + vpattern.cc \ + vsegment.cc \ + vselection.cc \ + vstroke.cc \ + vvisitor.cc \ + vlayer_iface.cc \ + vlayer_iface.skel \ + vtext.cc \ + vtext_iface.cc \ + vtext_iface.skel \ + vclipgroup.cc \ + vcursor.cc + +libkarboncore_la_LIBADD = $(LIBFONTCONFIG_LIBS) + +libkarboncore_la_METASOURCES = \ + AUTO diff --git a/karbon/core/vclipgroup.cc b/karbon/core/vclipgroup.cc new file mode 100644 index 00000000..fb96f609 --- /dev/null +++ b/karbon/core/vclipgroup.cc @@ -0,0 +1,178 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qdom.h> + +#include <kdebug.h> + +#include "vclipgroup.h" +#include "vgroup.h" +#include "vcomposite.h" +#include "vsegment.h" +#include <vpainter.h> +#include "vtext.h" +VClipGroup::VClipGroup( VObject* parent, VState state ) : VGroup( parent, state ) {} +VClipGroup::VClipGroup( const VClipGroup& group ) : VGroup( group ) {} + +VClipGroup::~VClipGroup() { } + +void VClipGroup::draw( VPainter* painter, const KoRect* rect ) const +{ + return VGroup::draw( painter, rect ); + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + VObjectListIterator itr = m_objects; + + painter->save(); + + PathRenderer renderer( painter ); + kdDebug(38000) << "calling painter setClipPath" << endl; + painter->setClipPath(); + + VObject *obj = itr.current(); + obj->accept( renderer ); + ++itr; + + for( ; itr.current(); ++itr ) + itr.current()->draw( painter, rect ); + + painter->restore(); +} + +VClipGroup* VClipGroup::clone() const +{ + return new VClipGroup( *this ); +} + + +void VClipGroup::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "CLIP" ); + element.appendChild( me ); + + // save objects: + VObjectListIterator itr = m_objects; + + for( ; itr.current(); ++itr ) + itr.current()->save( me ); +} + +void VClipGroup::load( const QDomElement& element ) +{ + m_objects.setAutoDelete( true ); + m_objects.clear(); + m_objects.setAutoDelete( false ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + + if( e.tagName() == "COMPOSITE" || e.tagName() == "PATH" ) // TODO : remove COMPOSITE later + { + VPath* composite = new VPath( this ); + composite->load( e ); + append( composite ); + } + else if( e.tagName() == "GROUP" ) + { + VGroup* group = new VGroup( this ); + group->load( e ); + append( group ); + } + else if( e.tagName() == "CLIP" ) + { + VClipGroup* clip = new VClipGroup( this ); + clip->load( e ); + append( clip ); + } + else if( e.tagName() == "TEXT" ) + { +#ifdef HAVE_KARBONTEXT + VText *text = new VText( this ); + text->load( e ); + append( text ); +#endif + } + } + } +} + +PathRenderer::PathRenderer( VPainter *p_painter ) : VVisitor() +{ + m_painter = p_painter; +} + +PathRenderer::~PathRenderer() {} + +void PathRenderer::visitVSubpath( VSubpath& path ) +{ + if(!m_painter) return; + + if(path.isEmpty()) return; + + for(path.first(); VSegment *segment = path.current(); path.next() ) + { + KoPoint p1; + KoPoint p2; + KoPoint p3; + + QString buffer; + + if(segment->state() != VSegment::deleted) + { + if (segment->isBegin()) { + p1 = segment->point( 0 ); + + kdDebug(38000) << "calling painter.moveTo with " << p1 << endl; + m_painter->moveTo( p1 ); + } else if (segment->isCurve()) { + p1 = segment->point( 0 ); + p2 = segment->point( 1 ); + p3 = segment->point( 2 ); + + kdDebug(38000) << "calling painter.curveTo with " << p1 << " " << p2 << " " << p3 << endl; + m_painter->curveTo( p1, p2, p3 ); + + } else if (segment->isLine()) { + p1 = segment->point( 0 ); + kdDebug(38000) << "calling painter.lineTo with " << p1 << endl; + m_painter->lineTo( p1 ); + } + } + } + + VVisitor::visitVSubpath(path); + +// if( path.isClosed() ) m_painter->closePath(); +} + diff --git a/karbon/core/vclipgroup.h b/karbon/core/vclipgroup.h new file mode 100644 index 00000000..640f3b11 --- /dev/null +++ b/karbon/core/vclipgroup.h @@ -0,0 +1,64 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCLIP_H__ +#define __VCLIP_H__ + +#include "vgroup.h" +#include "vvisitor.h" +#include <koffice_export.h> +class VPainter; + +/** + * Base class for clipping conglomerates + * the first child element is used for clipping + */ + +class KARBONBASE_EXPORT VClipGroup : public VGroup +{ +public: + VClipGroup( VObject* parent, VState state = normal ); + VClipGroup ( const VClipGroup& group ); + + virtual ~VClipGroup(); + + virtual void draw( VPainter* painter, const KoRect* rect = 0L ) const; + + virtual VClipGroup* clone() const; + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); +}; + + +class PathRenderer : public VVisitor +{ +public: + PathRenderer( VPainter *p_painter ); + + virtual ~PathRenderer(); + +protected: + virtual void visitVSubpath( VSubpath& path ); + +private: + VPainter *m_painter; +}; + +#endif diff --git a/karbon/core/vcolor.cc b/karbon/core/vcolor.cc new file mode 100644 index 00000000..c82777eb --- /dev/null +++ b/karbon/core/vcolor.cc @@ -0,0 +1,358 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#include <qdom.h> + +#include "vcolor.h" +#include "vglobal.h" + + +VColor::VColor( VColorSpace colorSpace ) +{ + m_colorSpace = colorSpace; + m_opacity = 1.0; + + m_value[0] = 0.0; + m_value[1] = 0.0; + m_value[2] = 0.0; + m_value[3] = 0.0; +} + +VColor::VColor( const VColor& color ) +{ + m_colorSpace = color.m_colorSpace; + m_opacity = color.m_opacity; + + m_value[0] = color.m_value[0]; + m_value[1] = color.m_value[1]; + m_value[2] = color.m_value[2]; + m_value[3] = color.m_value[3]; +} + +VColor::VColor( const QColor& color ) +{ + m_colorSpace = rgb; + m_opacity = 1.0; + + m_value[0] = color.red() / 255.0; + m_value[1] = color.green() / 255.0; + m_value[2] = color.blue() / 255.0; +} + +VColor::operator QColor() const +{ + VColor copy( *this ); + copy.convertToColorSpace( rgb ); + + QColor color; + color.setRgb( int( 255 * copy[0] ), int( 255 * copy[1] ), int( 255 * copy[2] ) ); + + return color; +} + +void +VColor::setColorSpace( const VColorSpace colorSpace, bool convert ) +{ + if( convert ) + convertToColorSpace( colorSpace ); + + m_colorSpace = colorSpace; +} + +void +VColor::convertToColorSpace( const VColorSpace colorSpace ) +{ + // TODO: numerical stability. + // TODO: undercolor removal with cmyk. + + if( colorSpace == rgb ) + { + if( m_colorSpace == rgb ) + { + // Do nothing. + } + else if( m_colorSpace == cmyk ) + { + m_value[0] = 1.0 - kMin( 1.0f, m_value[0] + m_value[3] ); + m_value[1] = 1.0 - kMin( 1.0f, m_value[1] + m_value[3] ); + m_value[2] = 1.0 - kMin( 1.0f, m_value[2] + m_value[3] ); + } + else if( m_colorSpace == hsb ) + { + // Achromatic case (saturation == 0.0). + if( m_value[1] == 0.0 ) + { + // Set to brightness: + m_value[0] = m_value[2]; + m_value[1] = m_value[2]; + m_value[2] = m_value[2]; // For readability. + } + else + { + float hue6 = 6.0 * m_value[0]; + uint i = static_cast<uint>( hue6 ); + float f = hue6 - i; + + float m = m_value[2] * ( 1.0 - m_value[1] ); + float n = m_value[2] * ( 1.0 - m_value[1] * f ); + float k = m_value[2] * ( 1.0 - m_value[1] * ( 1.0 - f ) ); + + float r; + float g; + float b; + + switch( i ) + { + case 1: + r = n; + g = m_value[2]; + b = m; + break; + case 2: + r = m; + g = m_value[2]; + b = k; + break; + case 3: + r = m; + g = n; + b = m_value[2]; + break; + case 4: + r = k; + g = m; + b = m_value[2]; + break; + case 5: + r = m_value[2]; + g = m; + b = n; + break; + default: + r = m_value[2]; + g = k; + b = m; + } + + m_value[0] = r; + m_value[1] = g; + m_value[2] = b; + } + } + else if( m_colorSpace == gray ) + { + m_value[0] = m_value[0]; // For readability. + m_value[1] = m_value[0]; + m_value[2] = m_value[0]; + } + } + else if( colorSpace == cmyk ) + { + if( m_colorSpace == rgb ) + { + m_value[0] = 1.0 - m_value[0]; + m_value[1] = 1.0 - m_value[1]; + m_value[2] = 1.0 - m_value[2]; + m_value[3] = 0.0; + } + else if( m_colorSpace == cmyk ) + { + // Do nothing. + } + else if( m_colorSpace == hsb ) + { +// TODO + } + else if( m_colorSpace == gray ) + { + m_value[1] = 0.0; + m_value[2] = 0.0; + m_value[3] = 1.0 - m_value[0]; + m_value[0] = 0.0; + } + } + else if( colorSpace == hsb ) + { + if( m_colorSpace == rgb ) + { + if( + m_value[0] == m_value[1] && + m_value[1] == m_value[2] ) + { + // Arbitrary: + m_value[3] = m_value[0]; + m_value[1] = 0.0; + m_value[2] = 0.0; + } + else + { + float max; + float min; + + // Find maximum + minimum rgb component: + if( m_value[0] > m_value[1] ) + { + max = m_value[0]; + min = m_value[1]; + } + else + { + max = m_value[1]; + min = m_value[0]; + } + + if( m_value[2] > max ) + max = m_value[2]; + + if( m_value[2] < min ) + min = m_value[2]; + + + float hue; + const float diff = max - min; + + // Which rgb component is maximum? + if( max == m_value[0] ) + // Red: + hue = ( m_value[1] - m_value[2] ) * VGlobal::one_6 / diff; + else if( max == m_value[1] ) + // Green: + hue = ( m_value[2] - m_value[0] ) * VGlobal::one_6 / diff + VGlobal::one_3; + else + // Blue: + hue = ( m_value[0] - m_value[1] ) * VGlobal::one_6 / diff + VGlobal::two_3; + + if( hue < 0.0 ) + hue += 1.0; + + + m_value[0] = hue; + m_value[1] = diff / max; + m_value[2] = max; + } + } + else if( m_colorSpace == cmyk ) + { +// TODO + } + else if( m_colorSpace == hsb ) + { + // Do nothing. + } + else if( m_colorSpace == gray ) + { + m_value[1] = 0.0; + m_value[2] = m_value[0]; + m_value[0] = 0.0; + } + } + else if( colorSpace == gray ) + { + if( m_colorSpace == rgb ) + { + m_value[0] = + 0.3 * m_value[0] + + 0.59 * m_value[1] + + 0.11 * m_value[2]; + } + else if( m_colorSpace == cmyk ) + { + m_value[0] = + 1.0 - kMin( 1.0, + 0.3 * m_value[0] + + 0.59 * m_value[1] + + 0.11 * m_value[2] + + m_value[3] ); + } + else if( m_colorSpace == hsb ) + { + m_value[0] = m_value[2]; + } + else if( m_colorSpace == gray ) + { + // Do nothing. + } + } +} + +void +VColor::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "COLOR" ); + element.appendChild( me ); + + if( m_colorSpace != rgb ) + me.setAttribute( "colorSpace", m_colorSpace ); + if( m_opacity != 1.0 ) + me.setAttribute( "opacity", m_opacity ); + + if( m_colorSpace == gray ) + me.setAttribute( "v", m_value[0] ); + else + { + me.setAttribute( "v1", m_value[0] ); + me.setAttribute( "v2", m_value[1] ); + me.setAttribute( "v3", m_value[2] ); + + if( m_colorSpace == cmyk ) + me.setAttribute( "v4", m_value[3] ); + } +} + +void +VColor::load( const QDomElement& element ) +{ + switch( element.attribute( "colorSpace" ).toUShort() ) + { + case 1: + m_colorSpace = cmyk; break; + case 2: + m_colorSpace = hsb; break; + case 3: + m_colorSpace = gray; break; + default: + m_colorSpace = rgb; + } + + m_opacity = element.attribute( "opacity", "1.0" ).toFloat(); + + if( m_colorSpace == gray ) + m_value[0] = element.attribute( "v", "0.0" ).toFloat(); + else + { + m_value[0] = element.attribute( "v1", "0.0" ).toFloat(); + m_value[1] = element.attribute( "v2", "0.0" ).toFloat(); + m_value[2] = element.attribute( "v3", "0.0" ).toFloat(); + + if( m_colorSpace == cmyk ) + m_value[3] = element.attribute( "v4", "0.0" ).toFloat(); + } + + if( m_value[0] < 0.0 || m_value[0] > 1.0 ) + m_value[0] = 0.0; + if( m_value[1] < 0.0 || m_value[1] > 1.0 ) + m_value[1] = 0.0; + if( m_value[2] < 0.0 || m_value[2] > 1.0 ) + m_value[2] = 0.0; + if( m_value[3] < 0.0 || m_value[3] > 1.0 ) + m_value[3] = 0.0; +} + diff --git a/karbon/core/vcolor.h b/karbon/core/vcolor.h new file mode 100644 index 00000000..cf48370e --- /dev/null +++ b/karbon/core/vcolor.h @@ -0,0 +1,182 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOLOR_H__ +#define __VCOLOR_H__ + + +#include <qcolor.h> +#include <qstring.h> +#include <koffice_export.h> +class QDomElement; + + +/** + * This class keeps track of color properties. + * The actual color values can be represented in + * rgb and hsv color spaces. Also each color has + * a related opacity value. + * + * Default is opaque, rgb, black color. + */ + +class KARBONBASE_EXPORT VColor +{ +public: + enum VColorSpace + { + rgb = 0, /**< the RGB colorspace (red, green and blue components) */ + cmyk = 1, /**< the CMYK colorspace (cyan, magenta, yellow and black components) */ + hsb = 2, /**< the HSB colorspace (hue, saturation and brightnes components) */ + gray = 3 /**< the Gray colorspace (gray from black to white) */ + }; + + /** + * Constructs a new VColor with the specified colorspace. + * + * @param colorSpace the colorspace of the new color + */ + VColor( VColorSpace colorSpace = rgb ); + + /** + * Constructs a new VColor by copying data from the specified VColor + * + * @param color the color to copy from + */ + VColor( const VColor& color ); + + /** + * Constructs a new VColor by copying data from the specified QColor + * + * @param color the color to copy from + */ + VColor( const QColor& color ); + + /** + * Cast operator to QColor. + */ + operator QColor() const; + + /** + * Index operator to access color components. + * + * @param i the index of the color component to access + * @return the requested color component + */ + float operator[]( unsigned i ) const + { return m_value[i]; } + + /** + * Sets the first color component. + * + * @param v1 the new value of the first color component + */ + void set( float v1 ) + { m_value[0] = v1; } + + /** + * Sets the first and second color component. + * + * @param v1 the new value of the first color component + * @param v2 the new value of the second color component + */ + void set( float v1, float v2 ) + { m_value[0] = v1; m_value[1] = v2; } + + /** + * Sets the first, second and third color component. + * + * @param v1 the new value of the first color component + * @param v2 the new value of the second color component + * @param v3 the new value of the third color component + */ + void set( float v1, float v2, float v3 ) + { m_value[0] = v1; m_value[1] = v2; m_value[2] = v3; } + + /** + * Sets the first, second, third and fourth color component. + * + * @param v1 the new value of the first color component + * @param v2 the new value of the second color component + * @param v3 the new value of the third color component + * @param v4 the new value of the fourth color component + */ + void set( float v1, float v2, float v3, float v4 ) + { m_value[0] = v1; m_value[1] = v2; m_value[2] = v3; m_value[3] = v4; } + + /** + * Returns the color opacity. + * + * Opacity is a value ranging from 0.0 (fully transparent) to 1.0 (opaque). + * + * @return the color opacity + */ + float opacity() const { return m_opacity; } + + /** + * Sets the color opacity. + * + * @param opacity the new color opacity. + */ + void setOpacity( float opacity ) { m_opacity = opacity; } + + /** + * Returns the color's colorspace. + * + * @return the color's colorspace + */ + VColorSpace colorSpace() const { return m_colorSpace; } + + /** + * Sets the color's colorspace. + * + * The color is converted into the new colorspace by setting convert = true. + * + * @param colorSpace the new colorspace + * @param convert controls if color is converted into new colorspace + */ + void setColorSpace( const VColorSpace colorSpace, bool convert = true ); + + /** + * Save this color's state to xml. + * + * @param element the DOM element to which the attributes are saved + */ + void save( QDomElement& element ) const; + + /** + * Load this color's state from xml and initialize it accordingly. + * + * @param element the DOM element from which the attributes are read + */ + void load( const QDomElement& element ); + +private: + void convertToColorSpace( const VColorSpace colorSpace ); + + VColorSpace m_colorSpace; + + float m_value[4]; + float m_opacity; + + QString m_name; +}; + +#endif diff --git a/karbon/core/vcomposite.cc b/karbon/core/vcomposite.cc new file mode 100644 index 00000000..8cd61311 --- /dev/null +++ b/karbon/core/vcomposite.cc @@ -0,0 +1,775 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> +#include <qpainter.h> +#include <qwmatrix.h> +#include <qregexp.h> + +#include <KoPoint.h> +#include <KoRect.h> +#include <KoUnit.h> +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <KoGenStyles.h> + +#include "vcomposite.h" +#include "vcomposite_iface.h" +#include "vfill.h" +#include "vpainter.h" +#include "vsegment.h" +#include "vstroke.h" +#include "vvisitor.h" +#include "vpath.h" +#include "commands/vtransformcmd.h" +#include "vdocument.h" + +#include <kdebug.h> + + +VPath::VPath( VObject* parent, VState state ) + : VObject( parent, state ), m_fillRule( winding ) +{ + m_paths.setAutoDelete( true ); + + // add an initial path: + m_paths.append( new VSubpath( this ) ); + + // we need a stroke for boundingBox() at anytime: + m_stroke = new VStroke( this ); + m_fill = new VFill(); + + m_drawCenterNode = false; +} + +VPath::VPath( const VPath& composite ) + : VObject( composite ), SVGPathParser() +{ + m_paths.setAutoDelete( true ); + + VSubpath* path; + + VSubpathListIterator itr( composite.m_paths ); + for( itr.toFirst(); itr.current(); ++itr ) + { + path = itr.current()->clone(); + path->setParent( this ); + m_paths.append( path ); + } + + if ( composite.stroke() ) + setStroke( *composite.stroke() ); + + if ( composite.fill() ) + setFill( *composite.fill() ); + + m_drawCenterNode = false; + m_fillRule = composite.m_fillRule; + m_matrix = composite.m_matrix; +} + +VPath::~VPath() +{ +} + +DCOPObject* VPath::dcopObject() +{ + if ( !m_dcop ) + m_dcop = new VPathIface( this ); + + return m_dcop; +} + + +void +VPath::draw( VPainter* painter, const KoRect *rect ) const +{ + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + if( rect && !rect->intersects( boundingBox() ) ) + return; + + painter->save(); + + VSubpathListIterator itr( m_paths ); + + // draw simplistic contour: + if( state() == edit ) + { + for( itr.toFirst(); itr.current(); ++itr ) + { + if( !itr.current()->isEmpty() ) + { + painter->newPath(); + painter->setRasterOp( Qt::XorROP ); + painter->setPen( Qt::yellow ); + painter->setBrush( Qt::NoBrush ); + + VSubpathIterator jtr( *( itr.current() ) ); + for( ; jtr.current(); ++jtr ) + { + jtr.current()->draw( painter ); + } + + painter->strokePath(); + } + } + } + else if( state() != edit ) + { + // paint fill: + painter->newPath(); + painter->setFillRule( m_fillRule ); + + for( itr.toFirst(); itr.current(); ++itr ) + { + if( !itr.current()->isEmpty() ) + { + VSubpathIterator jtr( *( itr.current() ) ); + for( ; jtr.current(); ++jtr ) + { + jtr.current()->draw( painter ); + } + } + } + + painter->setRasterOp( Qt::CopyROP ); + painter->setPen( Qt::NoPen ); + painter->setBrush( *fill() ); + painter->fillPath(); + + // draw stroke: + painter->setPen( *stroke() ); + painter->setBrush( Qt::NoBrush ); + painter->strokePath(); + } + + painter->restore(); +} + +const KoPoint& +VPath::currentPoint() const +{ + return m_paths.getLast()->currentPoint(); +} + +bool +VPath::moveTo( const KoPoint& p ) +{ + // Append a new subpath if current subpath is not empty. + if( !m_paths.getLast()->isEmpty() ) + { + VSubpath* path = new VSubpath( this ); + m_paths.append( path ); + } + + return m_paths.getLast()->moveTo( p ); +} + +bool +VPath::lineTo( const KoPoint& p ) +{ + return m_paths.getLast()->lineTo( p ); +} + +bool +VPath::curveTo( + const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 ) +{ + return m_paths.getLast()->curveTo( p1, p2, p3 ); +} + +bool +VPath::curve1To( const KoPoint& p2, const KoPoint& p3 ) +{ + return m_paths.getLast()->curve1To( p2, p3 ); +} + +bool +VPath::curve2To( const KoPoint& p1, const KoPoint& p3 ) +{ + return m_paths.getLast()->curve2To( p1, p3 ); +} + +bool +VPath::arcTo( const KoPoint& p1, const KoPoint& p2, const double r ) +{ + return m_paths.getLast()->arcTo( p1, p2, r ); +} + +void +VPath::close() +{ + m_paths.getLast()->close(); + + // Append a new subpath. + VSubpath* path = new VSubpath( this ); + path->moveTo( currentPoint() ); + m_paths.append( path ); +} + +bool +VPath::isClosed() const +{ + return m_paths.getLast()->isEmpty() || m_paths.getLast()->isClosed(); +} + +void +VPath::combine( const VPath& composite ) +{ + VSubpathListIterator itr( composite.m_paths ); + for( ; itr.current(); ++itr ) + { + combinePath( *( itr.current() ) ); + } +} + +void +VPath::combinePath( const VSubpath& path ) +{ + VSubpath* p = path.clone(); + p->setParent( this ); + + // TODO: do complex inside tests instead: + // Make new segments clock wise oriented: + + m_paths.append( p ); + m_fillRule = fillMode(); +} + +bool +VPath::pointIsInside( const KoPoint& p ) const +{ + // Check if point is inside boundingbox. + if( !boundingBox().contains( p ) ) + return false; + + + VSubpathListIterator itr( m_paths ); + + for( itr.toFirst(); itr.current(); ++itr ) + { + if( itr.current()->pointIsInside( p ) ) + return true; + } + + return false; +} + +bool +VPath::intersects( const VSegment& segment ) const +{ + // Check if boundingboxes intersect. + if( !boundingBox().intersects( segment.boundingBox() ) ) + return false; + + + VSubpathListIterator itr( m_paths ); + + for( itr.toFirst(); itr.current(); ++itr ) + { + if( itr.current()->intersects( segment ) ) + return true; + } + + return false; +} + + +VFillRule +VPath::fillMode() const +{ + return ( m_paths.count() > 1 ) ? evenOdd : winding; +} + +const KoRect& +VPath::boundingBox() const +{ + if( m_boundingBoxIsInvalid ) + { + VSubpathListIterator itr( m_paths ); + itr.toFirst(); + + m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect(); + + for( ++itr; itr.current(); ++itr ) + m_boundingBox |= itr.current()->boundingBox(); + + if( !m_boundingBox.isNull() ) + { + // take line width into account: + m_boundingBox.setCoords( + m_boundingBox.left() - 0.5 * stroke()->lineWidth(), + m_boundingBox.top() - 0.5 * stroke()->lineWidth(), + m_boundingBox.right() + 0.5 * stroke()->lineWidth(), + m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() ); + } + m_boundingBoxIsInvalid = false; + } + + return m_boundingBox; +} + +VPath* +VPath::clone() const +{ + return new VPath( *this ); +} + +void +VPath::save( QDomElement& element ) const +{ + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "PATH" ); + element.appendChild( me ); + + VObject::save( me ); + + QString d; + saveSvgPath( d ); + me.setAttribute( "d", d ); + + //writeTransform( me ); + + // save fill rule if necessary: + if( !( m_fillRule == evenOdd ) ) + me.setAttribute( "fillRule", m_fillRule ); + } +} + +void +VPath::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + if( state() != deleted ) + { + docWriter->startElement( "draw:path" ); + + QString d; + saveSvgPath( d ); + docWriter->addAttribute( "svg:d", d ); + + double x = boundingBox().x(); + double y = boundingBox().y(); + double w = boundingBox().width(); + double h = boundingBox().height(); + + docWriter->addAttribute( "svg:viewBox", QString( "%1 %2 %3 %4" ).arg( x ).arg( y ).arg( w ).arg( h ) ); + docWriter->addAttributePt( "svg:x", x ); + docWriter->addAttributePt( "svg:y", y ); + docWriter->addAttributePt( "svg:width", w ); + docWriter->addAttributePt( "svg:height", h ); + + VObject::saveOasis( store, docWriter, mainStyles, index ); + + QWMatrix tmpMat; + tmpMat.scale( 1, -1 ); + tmpMat.translate( 0, -document()->height() ); + + QString transform = buildOasisTransform( tmpMat ); + if( !transform.isEmpty() ) + docWriter->addAttribute( "draw:transform", transform ); + + docWriter->endElement(); + } +} + +void +VPath::saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesobjectauto ) const +{ + if( m_fill ) + { + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -document()->height() ); + + // mirror fill before saving + VFill fill( *m_fill ); + fill.transform( mat ); + fill.saveOasis( mainStyles, stylesobjectauto ); + // save fill rule if necessary: + if( !( m_fillRule == evenOdd ) ) + stylesobjectauto.addProperty( "svg:fill-rule", "winding" ); + } +} + +void +VPath::transformByViewbox( const QDomElement &element, QString viewbox ) +{ + if( ! viewbox.isEmpty() ) + { + // allow for viewbox def with ',' or whitespace + QStringList points = QStringList::split( ' ', viewbox.replace( ',', ' ' ).simplifyWhiteSpace() ); + + double w = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) ); + double h = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) ); + double x = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ); + double y = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ); + + QWMatrix mat; + mat.translate( x-KoUnit::parseValue( points[0] ), y-KoUnit::parseValue( points[1] ) ); + mat.scale( w / KoUnit::parseValue( points[2] ) , h / KoUnit::parseValue( points[3] ) ); + VTransformCmd cmd( 0L, mat ); + cmd.visitVPath( *this ); + } +} + +bool +VPath::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + setState( normal ); + + QString viewbox; + + if( element.localName() == "path" ) + { + QString data = element.attributeNS( KoXmlNS::svg, "d", QString::null ); + if( data.length() > 0 ) + { + loadSvgPath( data ); + } + + m_fillRule = element.attributeNS( KoXmlNS::svg, "fill-rule", QString::null ) == "winding" ? winding : evenOdd; + + viewbox = element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ); + } + else if( element.localName() == "custom-shape" ) + { + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + if( e.namespaceURI() != KoXmlNS::draw ) + continue; + + if( e.localName() == "enhanced-geometry" ) + { + QString data = e.attributeNS( KoXmlNS::draw, "enhanced-path", QString::null ); + if( ! data.isEmpty() ) + loadSvgPath( data ); + + viewbox = e.attributeNS( KoXmlNS::svg, "viewBox", QString::null ); + } + } + } + } + + transformByViewbox( element, viewbox ); + + QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null ); + if( !trafo.isEmpty() ) + transformOasis( trafo ); + + return VObject::loadOasis( element, context ); +} + +void +VPath::load( const QDomElement& element ) +{ + setState( normal ); + + VObject::load( element ); + + QString data = element.attribute( "d" ); + if( data.length() > 0 ) + { + loadSvgPath( data ); + } + m_fillRule = element.attribute( "fillRule" ) == 0 ? evenOdd : winding; + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement child = list.item( i ).toElement(); + + if( child.tagName() == "PATH" ) + { + VSubpath path( this ); + path.load( child ); + + combinePath( path ); + } + else + { + VObject::load( child ); + } + } + } + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +void +VPath::loadSvgPath( const QString &d ) +{ + //QTime s;s.start(); + parseSVG( d, true ); + //kdDebug(38000) << "Parsing time : " << s.elapsed() << endl; +} + +void +VPath::saveSvgPath( QString &d ) const +{ + // save paths to svg: + VSubpathListIterator itr( m_paths ); + for( itr.toFirst(); itr.current(); ++itr ) + { + if( !itr.current()->isEmpty() ) + itr.current()->saveSvgPath( d ); + } +} + +void +VPath::svgMoveTo( double x1, double y1, bool ) +{ + moveTo( KoPoint( x1, y1 ) ); +} + +void +VPath::svgLineTo( double x1, double y1, bool ) +{ + lineTo( KoPoint( x1, y1 ) ); +} + +void +VPath::svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool ) +{ + curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x, y ) ); +} + +void +VPath::svgClosePath() +{ + close(); +} + +void +VPath::accept( VVisitor& visitor ) +{ + visitor.visitVPath( *this ); +} + +void +VPath::transform( const QString &transform ) +{ + VTransformCmd cmd( 0L, parseTransform( transform ) ); + cmd.visitVPath( *this ); +} + +void +VPath::transformOasis( const QString &transform ) +{ + VTransformCmd cmd( 0L, parseOasisTransform( transform ) ); + cmd.visitVPath( *this ); +} + +QWMatrix +VPath::parseTransform( const QString &transform ) +{ + QWMatrix result; + + // Split string for handling 1 transform statement at a time + QStringList subtransforms = QStringList::split(')', transform); + QStringList::ConstIterator it = subtransforms.begin(); + QStringList::ConstIterator end = subtransforms.end(); + for(; it != end; ++it) + { + QStringList subtransform = QStringList::split('(', (*it)); + + subtransform[0] = subtransform[0].stripWhiteSpace().lower(); + subtransform[1] = subtransform[1].simplifyWhiteSpace(); + QRegExp reg("[,( ]"); + QStringList params = QStringList::split(reg, subtransform[1]); + + if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) + subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); + + if(subtransform[0] == "rotate") + { + if(params.count() == 3) + { + double x = params[1].toDouble(); + double y = params[2].toDouble(); + + result.translate(x, y); + result.rotate(params[0].toDouble()); + result.translate(-x, -y); + } + else + result.rotate(params[0].toDouble()); + } + else if(subtransform[0] == "translate") + { + if(params.count() == 2) + result.translate(params[0].toDouble(), params[1].toDouble()); + else // Spec : if only one param given, assume 2nd param to be 0 + result.translate(params[0].toDouble() , 0); + } + else if(subtransform[0] == "scale") + { + if(params.count() == 2) + result.scale(params[0].toDouble(), params[1].toDouble()); + else // Spec : if only one param given, assume uniform scaling + result.scale(params[0].toDouble(), params[0].toDouble()); + } + else if(subtransform[0] == "skewx") + result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F); + else if(subtransform[0] == "skewy") + result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F); + else if(subtransform[0] == "skewy") + result.shear(0.0F, tan(params[0].toDouble() * VGlobal::pi_180)); + else if(subtransform[0] == "matrix") + { + if(params.count() >= 6) + result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble()); + } + } + + return result; +} + +QWMatrix +VPath::parseOasisTransform( const QString &transform ) +{ + QWMatrix result; + + // Split string for handling 1 transform statement at a time + QStringList subtransforms = QStringList::split(')', transform); + QStringList::ConstIterator it = subtransforms.begin(); + QStringList::ConstIterator end = subtransforms.end(); + for(; it != end; ++it) + { + QStringList subtransform = QStringList::split('(', (*it)); + + subtransform[0] = subtransform[0].stripWhiteSpace().lower(); + subtransform[1] = subtransform[1].simplifyWhiteSpace(); + QRegExp reg("[,( ]"); + QStringList params = QStringList::split(reg, subtransform[1]); + + if(subtransform[0].startsWith(";") || subtransform[0].startsWith(",")) + subtransform[0] = subtransform[0].right(subtransform[0].length() - 1); + + if(subtransform[0] == "rotate") + { + // TODO find out what oo2 really does when rotating, it seems severly broken + if(params.count() == 3) + { + double x = KoUnit::parseValue( params[1] ); + double y = KoUnit::parseValue( params[2] ); + + result.translate(x, y); + // oo2 rotates by radians + result.rotate( params[0].toDouble()*VGlobal::one_pi_180 ); + result.translate(-x, -y); + } + else + { + // oo2 rotates by radians + result.rotate( params[0].toDouble()*VGlobal::one_pi_180 ); + } + } + else if(subtransform[0] == "translate") + { + if(params.count() == 2) + { + double x = KoUnit::parseValue( params[0] ); + double y = KoUnit::parseValue( params[1] ); + result.translate(x, y); + } + else // Spec : if only one param given, assume 2nd param to be 0 + result.translate( KoUnit::parseValue( params[0] ) , 0); + } + else if(subtransform[0] == "scale") + { + if(params.count() == 2) + result.scale(params[0].toDouble(), params[1].toDouble()); + else // Spec : if only one param given, assume uniform scaling + result.scale(params[0].toDouble(), params[0].toDouble()); + } + else if(subtransform[0] == "skewx") + result.shear(tan(params[0].toDouble()), 0.0F); + else if(subtransform[0] == "skewy") + result.shear(tan(params[0].toDouble()), 0.0F); + else if(subtransform[0] == "skewy") + result.shear(0.0F, tan(params[0].toDouble())); + else if(subtransform[0] == "matrix") + { + if(params.count() >= 6) + result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), KoUnit::parseValue( params[4] ), KoUnit::parseValue( params[5] ) ); + } + } + + return result; +} + +QString +VPath::buildSvgTransform() const +{ + return buildSvgTransform( m_matrix ); +} + +QString +VPath::buildSvgTransform( const QWMatrix &mat ) const +{ + QString transform; + if( !mat.isIdentity() ) + { + transform = QString( "matrix(%1, %2, %3, %4, %5, %6)" ).arg( mat.m11() ) + .arg( mat.m12() ) + .arg( mat.m21() ) + .arg( mat.m22() ) + .arg( mat.dx() ) + .arg( mat.dy() ); + } + return transform; +} + +QString +VPath::buildOasisTransform() const +{ + return buildSvgTransform( m_matrix ); +} + +QString +VPath::buildOasisTransform( const QWMatrix &mat ) const +{ + QString transform; + if( !mat.isIdentity() ) + { + transform = QString( "matrix(%1, %2, %3, %4, %5pt, %6pt)" ).arg( mat.m11() ) + .arg( mat.m12() ) + .arg( mat.m21() ) + .arg( mat.m22() ) + .arg( mat.dx() ) + .arg( mat.dy() ); + } + return transform; +} diff --git a/karbon/core/vcomposite.h b/karbon/core/vcomposite.h new file mode 100644 index 00000000..e786294b --- /dev/null +++ b/karbon/core/vcomposite.h @@ -0,0 +1,244 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOMPOSITE_H__ +#define __VCOMPOSITE_H__ + + +#include <qptrlist.h> + +#include <KoPoint.h> + +#include "vobject.h" +#include "svgpathparser.h" +#include "vfillrule.h" +#include <koffice_export.h> + +class QDomElement; +class VPainter; +class VSegment; +class VVisitor; +class VSubpath; + +typedef QPtrList<VSubpath> VSubpathList; +typedef QPtrListIterator<VSubpath> VSubpathListIterator; + + +/** + * A composite path consists of one or many subpaths. + */ + +class KARBONBASE_EXPORT VPath : public VObject, SVGPathParser +{ +public: + VPath( VObject* parent, VState state = normal ); + VPath( const VPath& path ); + virtual ~VPath(); + + virtual DCOPObject* dcopObject(); + + /** + * Returns the knot of the last segment of the last subpath. + */ + const KoPoint& currentPoint() const; + + + bool moveTo( const KoPoint& p ); + bool lineTo( const KoPoint& p ); + + /* + curveTo(): + + p1 p2 + O ____ O + : _/ \_ : + :/ \: + x x + currP p3 + */ + + bool curveTo( + const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 ); + + /* + curve1To(): + + p2 + ____ O + __/ \ : + / \: + x x + currP p3 + */ + + bool curve1To( const KoPoint& p2, const KoPoint& p3 ); + + /* + curve2To(): + + p1 + O ____ + : / \__ + :/ \ + x x + currP p3 + */ + + bool curve2To( const KoPoint& p1, const KoPoint& p3 ); + + /** + * A convenience function to aproximate a circular arc with a + * bezier curve. Input: 2 tangent vectors and a radius (same as in PostScript). + */ + + /* + arcTo(): + + p1 x....__--x....x p2 + : _/ + : / + :/ + | + x + | + | + x currP + */ + bool arcTo( const KoPoint& p1, const KoPoint& p2, double r ); + + /** + * Closes the current subpath. + */ + void close(); + + bool isClosed() const; + /** + * Combines two composite paths. For example, the letter "O" is a combination + * of a larger and a smaller ellipitical path. + */ + void combine( const VPath& path ); + + /** + * Adds a path to the composite path. + */ + void combinePath( const VSubpath& path ); + + + /** + * Returns true if point p is located inside the composite. + */ + bool pointIsInside( const KoPoint& p ) const; + + + /** + * Returns true if the segment intersects this composite. + */ + bool intersects( const VSegment& segment ) const; + + + const VSubpathList& paths() const + { + return m_paths; + } + + virtual const KoRect& boundingBox() const; + + + VFillRule fillMode() const; + + // TODO remove these functions. + VFillRule fillRule() const + { + return m_fillRule; + } + + void setFillRule( VFillRule fillRule ) + { + m_fillRule = fillRule; + } + + + virtual void draw( VPainter *painter, const KoRect* rect = 0L ) const; + + bool drawCenterNode() const + { + return m_drawCenterNode; + } + + void setDrawCenterNode( bool drawCenterNode = true ) + { + m_drawCenterNode = drawCenterNode; + } + + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VPath* clone() const; + + virtual void accept( VVisitor& visitor ); + + void transform( const QString &transform ); + void transformOasis( const QString &transform ); + + static QWMatrix parseTransform( const QString &transform ); + + void transform( const QWMatrix &mat ) + { + m_matrix *= mat; + } + + + void loadSvgPath( const QString & ); + void saveSvgPath( QString & ) const; + +protected: + QString buildSvgTransform() const; + QString buildSvgTransform( const QWMatrix &mat ) const; + QString buildOasisTransform() const; + QString buildOasisTransform( const QWMatrix &mat ) const; + + void transformByViewbox( const QDomElement &element, QString viewbox ); + + /// For svg path data parsing. + virtual void svgMoveTo( double x1, double y1, bool abs = true ); + virtual void svgLineTo( double x1, double y1, bool abs = true ); + virtual void svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool abs = true ); + virtual void svgClosePath(); + + virtual void saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesojectauto ) const; + QWMatrix parseOasisTransform( const QString &transform ); + +protected: + QWMatrix m_matrix; + +private: + /** + * List of subpaths. + */ + VSubpathList m_paths; + + /// Should a center node be drawn? + bool m_drawCenterNode; + VFillRule m_fillRule : 1; +}; + +#endif diff --git a/karbon/core/vcomposite_iface.cc b/karbon/core/vcomposite_iface.cc new file mode 100644 index 00000000..2cc07c53 --- /dev/null +++ b/karbon/core/vcomposite_iface.cc @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vcomposite_iface.h" +#include "vcomposite.h" + +VPathIface::VPathIface( VPath *composite ) + : VObjectIface( composite ), m_composite( composite ) +{ +} + +bool +VPathIface::moveTo( double x, double y ) +{ + return m_composite->moveTo( KoPoint( x, y ) ); +} + +bool +VPathIface::lineTo( double x, double y ) +{ + return m_composite->lineTo( KoPoint( x, y ) ); +} + +bool +VPathIface::curveTo( double x1, double y1, double x2, double y2, double x3, double y3 ) +{ + return m_composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x3, y3 ) ); +} + +bool +VPathIface::curve1To( double x2, double y2, double x3, double y3 ) +{ + return m_composite->curve1To( KoPoint( x2, y2 ), KoPoint( x3, y3 ) ); +} + +bool +VPathIface::curve2To( double x1, double y1, double x2, double y2 ) +{ + return m_composite->curve2To( KoPoint( x1, y1 ), KoPoint( x2, y2 ) ); +} + +bool +VPathIface::arcTo( double x1, double y1, double x2, double y2, double r ) +{ + return m_composite->arcTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), r ); +} + +void +VPathIface::close() +{ + m_composite->close(); +} + diff --git a/karbon/core/vcomposite_iface.h b/karbon/core/vcomposite_iface.h new file mode 100644 index 00000000..6295047c --- /dev/null +++ b/karbon/core/vcomposite_iface.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOMPOSITE_IFACE_H__ +#define __VCOMPOSITE_IFACE_H__ + +#include "vobject_iface.h" + +class VPath; + +class VPathIface : public VObjectIface +{ + K_DCOP + +public: + VPathIface( VPath *composite ); + +k_dcop: + bool moveTo( double x, double y ); + bool lineTo( double x, double y ); + bool curveTo( double x1, double y1, double x2, double y2, double x3, double y3 ); + bool curve1To( double x2, double y2, double x3, double y3 ); + bool curve2To( double x1, double y1, double x2, double y2 ); + bool arcTo( double x1, double y1, double x2, double y2, double r ); + void close(); + + //bool drawCenterNode() const; + //void setDrawCenterNode( bool drawCenterNode = true ); + +private: + VPath *m_composite; +}; + +#endif diff --git a/karbon/core/vcursor.cc b/karbon/core/vcursor.cc new file mode 100644 index 00000000..ed9d1f8d --- /dev/null +++ b/karbon/core/vcursor.cc @@ -0,0 +1,166 @@ +/* This file is part of the KDE project + Copyright (C) 2006 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vcursor.h" +#include <qbitmap.h> + +static const char* const cminus[] = { +"16 16 6 1", +" c Gray0", +". c #939393", +"X c Gray63", +"o c #aeaeae", +"O c None", +"+ c Gray100", +"OOOOo XXoOOOO", +"OOo ++++ XoOOO", +"OO ++++++++ XoOO", +"Oo ++++++++ XXoO", +"O ++++++++++ XoO", +"O ++ ++ XoO", +"O ++ ++ XoO", +"O ++++++++++ XoO", +"Oo ++++++++ .oOO", +"OO ++++++++ .oOO", +"OOo ++++ .oOO", +"OOOOo O XoO", +"OOOOOOOOOOO Xo", +"OOOOOOOOOOOO X", +"OOOOOOOOOOOOO ", +"OOOOOOOOOOOOOO " +}; + +static const char* const cplus[] = { +"16 16 6 1", +" c Gray0", +". c #939393", +"X c Gray63", +"o c #aeaeae", +"O c None", +"+ c Gray100", +"OOOo XXoOOOOO", +"Oo ++++ XoOOOO", +"O ++++++++ XoOOO", +"o +++ +++ XXoOO", +" ++++ ++++ XoOO", +" ++ ++ XoOO", +" ++ ++ XoOO", +" ++++ ++++ XoOO", +"o +++ +++ .oOOO", +"O ++++++++ .oOOO", +"Oo ++++ .oOOO", +"OOOo O XoOO", +"OOOOOOOOOO XoO", +"OOOOOOOOOOO XO", +"OOOOOOOOOOOO O", +"OOOOOOOOOOOOO O" +}; + +QCursor VCursor::createCursor( CursorType type ) +{ + switch( type ) + { + case CrossHair: + return crossHair(); + break; + case ZoomPlus: + return QCursor( QPixmap( ( const char**) cplus ), -1, -1 ); + break; + case ZoomMinus: + return QCursor( QPixmap( ( const char**) cminus ), -1, -1 ); + break; + case NeedleArrow: + return needleArrow(); + break; + default: return QCursor( Qt::arrowCursor ); + } +} + +QCursor VCursor::createCursor( const char * bitmap[], const char * mask[], int hotX, int hotY ) +{ + // the cursor bitmap and mask + QBitmap b, m; + + b = QPixmap( (const char**) bitmap ); + m = QPixmap( (const char**) mask ); + + return QCursor( b, m, hotX, hotY ); +} + +QCursor VCursor::crossHair() +{ + static unsigned char cross_bits[] = { + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0xff, 0x7f, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00}; + + QBitmap b = QBitmap( 15, 15, cross_bits, true ); + QBitmap m = b.createHeuristicMask( false ); + + return QCursor( b, m, 7, 7 ); +} + +QCursor VCursor::needleArrow() +{ + static unsigned char needle_bits[] = { + 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x60, 0x00, 0xc0, 0x00, 0xc0, 0x01, + 0x80, 0x03, 0x80, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x3e, 0x00, 0x7e, + 0x00, 0x7c, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x00}; + + QBitmap b = QBitmap( 16, 16, needle_bits, true ); + QBitmap m = b.createHeuristicMask( false ); + + return QCursor( b, m, 2, 0 ); +} + +QCursor VCursor::needleMoveArrow() +{ + static unsigned char needle_move_bits[] = { + 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x60, 0x00, 0xc0, 0x00, 0xc0, 0x01, + 0x80, 0x03, 0x80, 0x07, 0x10, 0x0f, 0x38, 0x1f, 0x54, 0x3e, 0xfe, 0x7e, + 0x54, 0x7c, 0x38, 0x1c, 0x10, 0x18, 0x00, 0x00}; + + QBitmap b = QBitmap( 16, 16, needle_move_bits, true ); + QBitmap m = b.createHeuristicMask( false ); + + return QCursor( b, m, 2, 0 ); +} + +QCursor VCursor::horzMove() +{ +/* + #define horzMove_width 15 + #define horzMove_height 15 + static unsigned char horzMove_bits[] = { + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x90, 0x04, + 0x98, 0x0c, 0xfc, 0x1f, 0x98, 0x0c, 0x90, 0x04, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00}; +*/ + #define horzMove_width 15 + #define horzMove_height 15 + static unsigned char horzMove_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x0c, 0x18, 0xfe, 0x3f, 0x0c, 0x18, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + QBitmap b = QBitmap( 15, 15, horzMove_bits, true ); + QBitmap m = b.createHeuristicMask( false ); + + return QCursor( b, m, 7, 7 ); +} diff --git a/karbon/core/vcursor.h b/karbon/core/vcursor.h new file mode 100644 index 00000000..84c89648 --- /dev/null +++ b/karbon/core/vcursor.h @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Copyright (C) 2006 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCURSOR_H__ +#define __VCURSOR_H__ + +#include <qcursor.h> +#include <koffice_export.h> + +/** +* A helper class for easily creating cursors from XPMs. +* +* One can create a predefined unthemed cursor or create a cursor from two given XMPs, +* the cursor bitmap and the cursor mask. +*/ +class KARBONBASE_EXPORT VCursor +{ +public: + /** Predefined cursor types */ + enum CursorType + { + CrossHair = 0, /**< unthemed crosshair cursor */ + ZoomPlus = 1, /**< zoom in cursor */ + ZoomMinus = 2, /**< zoom out cursor */ + NeedleArrow = 3 /**< needle arrow */ + }; + + /** + * Creates a predefined cursor of the specified type. + * + * @param type the requested cursor id + * @return the predefined cursor + */ + static QCursor createCursor( CursorType type ); + + /** + * Creates a cursor from two specified XPM images. + * This is only a wrapper function for a QCursor ctor. + */ + static QCursor createCursor( const char * bitmap[], const char * mask[], int hotX = -1, int hotY = -1 ); + + /** crosshair cursor */ + static QCursor crossHair(); + + /** needle arraow cursor */ + static QCursor needleArrow(); + + /** needle arrow with four way arrow */ + static QCursor needleMoveArrow(); + + static QCursor horzMove(); + +private: + // prevent instantiation + VCursor() {}; +}; + +#endif diff --git a/karbon/core/vdashpattern.cc b/karbon/core/vdashpattern.cc new file mode 100644 index 00000000..e758e824 --- /dev/null +++ b/karbon/core/vdashpattern.cc @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include "vdashpattern.h" + +VDashPattern::VDashPattern( double offset ) + : m_offset( offset ) +{ +} + +void +VDashPattern::save( QDomElement& element ) const +{ + if( m_array.size() != 0 ) + { + QDomElement me = element.ownerDocument().createElement( "DASHPATTERN" ); + element.appendChild( me ); + + if( m_offset != 0.0 ) + me.setAttribute( "offset", m_offset ); + + QDomElement dash; + + QValueListConstIterator<float> itr; + for( itr = m_array.begin(); itr != m_array.end(); ++itr ) + { + dash = element.ownerDocument().createElement( "DASH" ); + me.appendChild( dash ); + dash.setAttribute( "l", *( itr ) ); + } + } +} + +void +VDashPattern::load( const QDomElement& element ) +{ + m_offset = element.attribute( "offset", "0.0" ).toDouble(); + + float value; + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + if( e.tagName() == "DASH" ) + { + value = e.attribute( "l", "0.0" ).toFloat(); + if( value < 0.0 ) + value = 0.0; + + m_array.append( value ); + } + } + } +} + diff --git a/karbon/core/vdashpattern.h b/karbon/core/vdashpattern.h new file mode 100644 index 00000000..1abf4e41 --- /dev/null +++ b/karbon/core/vdashpattern.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VDASHPATTERN_H__ +#define __VDASHPATTERN_H__ + +#include <qvaluelist.h> +#include <koffice_export.h> + +class QDomElement; + + +/** + * The dash pattern consistes of a sequence of on/off values. + * For example 10 5 5 10 would result in a dash of 10 pixels, + * next 5 pixels no dash, then 5 pixels of dashing, finally 10 pixels + * of no dash. This sequence is repeated until the whole outline is dashed. + * + * Also it supports an offset value for when to start the dashing. + * + * Default is no dashes. + */ + +class KARBONBASE_EXPORT VDashPattern +{ +public: + VDashPattern( double dashOffset = 0.0 ); + + const QValueList<float>& array() const { return m_array; } + void setArray( const QValueList<float>& array ) + { m_array = array; } + + // dash offset: + float offset() const { return m_offset; } + void setOffset( float offset ) { m_offset = offset; } + + void save( QDomElement& element ) const; + void load( const QDomElement& element ); + +private: + QValueList<float> m_array; + float m_offset; +}; + +#endif + diff --git a/karbon/core/vdocument.cc b/karbon/core/vdocument.cc new file mode 100644 index 00000000..d87ad368 --- /dev/null +++ b/karbon/core/vdocument.cc @@ -0,0 +1,323 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include "vdocument.h" +#include "vselection.h" +#include "vvisitor.h" +#include "vlayer.h" +#include "vstroke.h" +#include "vdashpattern.h" +#include "vpainter.h" + +#include <KoStore.h> +#include <KoPageLayout.h> +#include <KoXmlWriter.h> + +#include <kdebug.h> + +VDocument::VDocument() + : VObject( 0L ), + m_width(0.), m_height(0.), + m_selectionMode( VDocument::ActiveLayer ), + m_unit( KoUnit::U_MM ) +{ + m_selection = new VSelection( this ); + + // create a layer. we need at least one: + m_layers.setAutoDelete( true ); + m_layers.append( new VLayer( this ) ); + m_activeLayer = m_layers.getLast(); + m_activeLayer->setSelected( true ); + + m_saveAsPath = true; +} + +VDocument::VDocument( const VDocument& document ) + : VObject( document ), m_width(0), m_height(0) +{ + m_selection = new VSelection( this ); +// TODO +} + +VDocument::~VDocument() +{ + delete( m_selection ); +} + +void +VDocument::drawPage( VPainter *p, const KoPageLayout &pl, bool showPageMargins ) const +{ + p->setPen( Qt::black ); + p->setBrush( Qt::white ); + p->drawRect( 0, 0, m_width, m_height ); + + p->setPen( Qt::NoPen ); + p->setBrush( Qt::black ); + p->drawRect( m_width, - 2, 2, m_height ); + p->drawRect( 0, - 2, m_width, 2 ); + //p->drawRect( 0, m_height - 1, m_width, 1 ); + // Draw Grid + if( m_gridData.isShow ) + { + VStroke s( 0, 1 ); + s.setColor( m_gridData.color ); + double dx = m_gridData.freq.width(); + double dy = m_gridData.freq.height(); + p->setPen( s ); + p->setBrush( Qt::NoBrush ); + KoPoint p0( dx, dy ); + while( p0.x() < m_width ) + { + p->newPath(); + p->moveTo( KoPoint( p0.x(), 0 ) ); + p->lineTo( KoPoint( p0.x(), m_height ) ); + p->strokePath(); + + p0.rx() += dx; + } + while( p0.y() < m_height ) + { + p->newPath(); + p->moveTo( KoPoint( 0, p0.y() ) ); + p->lineTo( KoPoint( m_width, p0.y() ) ); + p->strokePath(); + + p0.ry() += dy; + } + } + // Draw page margins + if( showPageMargins ) + { + int ml = int( pl.ptLeft ); + int mt = int( pl.ptTop ); + int mr = int( pl.ptRight ); + int mb = int( pl.ptBottom ); + + VStroke s( 0, 1 ); + s.setColor( Qt::blue ); + QValueList<float> dashes; + s.dashPattern().setArray( dashes << 5 << 5 ); + p->setPen( s ); + p->setBrush( Qt::NoBrush ); + p->drawRect(ml, mt, m_width-ml-mr, m_height-mt-mb); + } +} + +void +VDocument::draw( VPainter *painter, const KoRect* rect ) const +{ + QPtrListIterator<VLayer> itr = m_layers; + + for ( ; itr.current(); ++itr ) + { + itr.current()->draw( painter, rect ); + } +} + +void +VDocument::insertLayer( VLayer* layer ) +{ +// if ( pos == -1 || !m_layers.insert( layer, pos )) + m_layers.append( layer ); + m_activeLayer = layer; +} // VDocument::insertLayer + +void +VDocument::removeLayer( VLayer* layer ) +{ + m_layers.remove( layer ); + if ( m_layers.count() == 0 ) + m_layers.append( new VLayer( this ) ); + m_activeLayer = m_layers.getLast(); +} // VDocument::removeLayer + +bool VDocument::canRaiseLayer( VLayer* layer ) +{ + int pos = m_layers.find( layer ); + return (pos != int( m_layers.count() ) - 1 && pos >= 0 ); +} + +bool VDocument::canLowerLayer( VLayer* layer ) +{ + int pos = m_layers.find( layer ); + return (pos>0); +} + +void +VDocument::raiseLayer( VLayer* layer ) +{ + int pos = m_layers.find( layer ); + if( pos != int( m_layers.count() ) - 1 && pos >= 0 ) + { + VLayer* layer = m_layers.take( pos ); + m_layers.insert( pos + 1, layer ); + } +} // VDocument::raiseLayer + +void +VDocument::lowerLayer( VLayer* layer ) +{ + int pos = m_layers.find( layer ); + if ( pos > 0 ) + { + VLayer* layer = m_layers.take( pos ); + m_layers.insert( pos - 1, layer ); + } +} // VDocument::lowerLayer + +int +VDocument::layerPos( VLayer* layer ) +{ + return m_layers.find( layer ); +} // VDocument::layerPos + +void +VDocument::setActiveLayer( VLayer* layer ) +{ + if ( m_layers.find( layer ) != -1 ) + m_activeLayer = layer; +} // VDocument::setActiveLayer + +void +VDocument::append( VObject* object ) +{ + m_activeLayer->append( object ); +} + +QDomDocument +VDocument::saveXML() const +{ + QDomDocument doc; + QDomElement me = doc.createElement( "DOC" ); + doc.appendChild( me ); + save( me ); + return doc; +} + +void +VDocument::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles ) const +{ + docWriter->startElement( "draw:page" ); + docWriter->addAttribute( "draw:name", name()); + docWriter->addAttribute( "draw:id", "page1"); + docWriter->addAttribute( "draw:master-page-name", "Default"); + + // save objects: + VLayerListIterator itr( m_layers ); + + int index = 0; + for ( ; itr.current(); ++itr ) + itr.current()->saveOasis( store, docWriter, mainStyles, ++index ); + + docWriter->endElement(); // draw:page +} + +void +VDocument::save( QDomElement& me ) const +{ + me.setAttribute( "mime", "application/x-karbon" ), + me.setAttribute( "version", "0.1" ); + me.setAttribute( "editor", "Karbon14" ); + me.setAttribute( "syntaxVersion", "0.1" ); + if( m_width > 0. ) + me.setAttribute( "width", m_width ); + if( m_height > 0. ) + me.setAttribute( "height", m_height ); + me.setAttribute( "unit", KoUnit::unitName( m_unit ) ); + + // save objects: + VLayerListIterator itr( m_layers ); + + for ( ; itr.current(); ++itr ) + itr.current()->save( me ); +} + + +VDocument* +VDocument::clone() const +{ + return new VDocument( *this ); +} + +void +VDocument::load( const QDomElement& doc ) +{ + loadXML( doc ); +} + +bool +VDocument::loadXML( const QDomElement& doc ) +{ + if( doc.attribute( "mime" ) != "application/x-karbon" || + doc.attribute( "syntaxVersion" ) != "0.1" ) + { + return false; + } + + m_layers.clear(); + + m_width = doc.attribute( "width", "800.0" ).toDouble(); + m_height = doc.attribute( "height", "550.0" ).toDouble(); + + m_unit = KoUnit::unit( doc.attribute( "unit", KoUnit::unitName( m_unit ) ) ); + + loadDocumentContent( doc ); + return true; +} + +void +VDocument::loadDocumentContent( const QDomElement& doc ) +{ + QDomNodeList list = doc.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + + if( e.tagName() == "LAYER" ) + { + VLayer* layer = new VLayer( this ); + layer->load( e ); + insertLayer( layer ); + } + } + } +} + +bool +VDocument::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + return m_layers.current()->loadOasis( element, context ); +} + +void +VDocument::accept( VVisitor& visitor ) +{ + visitor.visitVDocument( *this ); +} + +QString +VDocument::objectName( const VObject *obj ) const +{ + QMap<const VObject *, QString>::ConstIterator it = m_objectNames.find( obj ); + return it == m_objectNames.end() ? 0L : it.data(); +} diff --git a/karbon/core/vdocument.h b/karbon/core/vdocument.h new file mode 100644 index 00000000..577dd1c2 --- /dev/null +++ b/karbon/core/vdocument.h @@ -0,0 +1,327 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef VDOCUMENT_H +#define VDOCUMENT_H + +#include <KoUnit.h> + +#include <qstring.h> +#include <qptrlist.h> +#include <qptrdict.h> + +#include "vobject.h" + +#include "karbon_grid_data.h" +#include <koffice_export.h> + +class QDomDocument; +class QDomElement; +class VSelection; +class VLayer; +class KoPageLayout; + +typedef QPtrList<VLayer> VLayerList; +typedef QPtrListIterator<VLayer> VLayerListIterator; + + +/** + * All non-visual, static doc info is in here. + * The karbon part uses this class. + * Filters can use this class as well instead of + * the visually oriented karbon part. + */ + +class KARBONBASE_EXPORT VDocument : public VObject +{ +public: + /** The different selection modes */ + enum VSelectionMode { + ActiveLayer, /**< selection within the active layer */ + VisibleLayers, /**< selection within all visible layers */ + SelectedLayers, /**< selection within all selected layers */ + AllLayers /**< selection within all layers */ + }; + + /** + * Constructs a new document. + */ + VDocument(); + + /** + * Copy constructor. + * + * @param document the document to copy properties from + */ + VDocument( const VDocument& document ); + + /** + * Destroys the document and all of the layers. + */ + virtual ~VDocument(); + + virtual void draw( VPainter* painter, const KoRect* rect ) const; + + /** + * Draw the document frame to a painting device. + * + * @param painter abstraction that is used to render to a painting device. + * @param pl layout describing the page to draw on (restricting the painter) + * @param drawPageMargins if @c true, also draw the crop marks for the page margins, + * otherwise, don't draw them. + */ + void drawPage( VPainter *painter, const KoPageLayout &pl, bool drawPageMargins ) const; + + /** + * Returns document width. + * + * @return the document's width + */ + double width() const { return m_width; } + + /** + * Returns document height. + * + * @return the document's height + */ + double height() const { return m_height; } + + /** + * Sets document width. + * + * @param width the new document width + */ + void setWidth( double width ) { m_width = width; m_boundingBox.setWidth( width ); } + + /** + * Sets document height. + * + * @param height the new document height + */ + void setHeight( double height ) { m_height = height; m_boundingBox.setHeight( height ); } + + /** + * Returns document unit. + * + * @return the document's unit + */ + KoUnit::Unit unit() const + { return m_unit; } + + /** + * Sets document unit. + * + * @param unit the new document unit + */ + void setUnit( KoUnit::Unit unit ) + { m_unit = unit; } + + /** + * Checks if specified layer can be raised. + * + * A layer can be raised if there is more than one layer and the specified layer + * is not already at the top. + * + * @param layer the layer to check + * @return true if layer can be raised, else false + */ + bool canRaiseLayer( VLayer* layer ); + + /** + * Checks if specified layer can be lowered. + * + * A layer can be lowered if there is more than one layer and the specified layer + * is not already at the bottom. + * + * @param layer the layer to check + * @return true if layer can be lowered, else false + */ + bool canLowerLayer( VLayer* layer ); + + /** + * Raises the layer. + * + * @param layer the layer to raise + */ + void raiseLayer( VLayer* layer ); + + /** + * Lowers the layer. + * + * @param layer the layer to lower + */ + void lowerLayer( VLayer* layer ); + + /** + * Returns the position of the specified layer. + * + * @param layer the layer to retrieve the position for + * @return the layer position + */ + int layerPos( VLayer* layer ); + + /** + * Inserts a new layer. + * + * The layer is appended at the end, on top of all other layers, and is activated. + * + * @param layer the layer to insert + */ + void insertLayer( VLayer* layer ); + + /** + * Removes the layer. + * + * If there is no layer left, a new layer is created, inserted and activated. + * + * @param layer the layer to remove + */ + void removeLayer( VLayer* layer ); + + /** + * Sets the active layer. + * + * The specified layer is set active, if it is found in the layer list. + * + * @param layer the layer to set active + */ + void setActiveLayer( VLayer* layer ); + + /** + * Returns a pointer to the active layer. + * + * @return the currently active layer + */ + VLayer* activeLayer() const { return m_activeLayer; } + + /** + * Returns the list of layers. + */ + const VLayerList& layers() const { return m_layers; } + + QDomDocument saveXML() const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles ) const; + enum { STYLE_GRAPHICAUTO = 20, STYLE_LINEAR_GRADIENT, STYLE_RADIAL_GRADIENT, STYLE_STROKE }; + bool loadXML( const QDomElement& doc ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + void loadDocumentContent( const QDomElement& doc ); + + virtual VDocument* clone() const; + + virtual void accept( VVisitor& visitor ); + + + /** + * Returns a pointer to the selection. + * + * @return the document's selection + */ + VSelection* selection() const + { return m_selection; } + + /** + * Returns the selection mode. + * + * @return the actual selection mode + */ + VSelectionMode selectionMode() { return m_selectionMode; } + + /** + * Sets the selection mode. + * + * @param mode the new selection mode + */ + void setSelectionMode( VSelectionMode mode ) { m_selectionMode = mode; } + + /** + * Appends a new object to the active layer. + * + * @param object the object to append + */ + void append( VObject* object ); + + /** + * Returns custom name of specified object. + * + * @param obj the object to retrieve name for + * @return the custom name of the object or an empty string if no custom name is set + */ + QString objectName( const VObject *obj ) const; + + /** + * Sets custom name of specified object. + * + * By default all object have generic names like path, rectangle or text that + * is defined within the object's class. + * + * @param obj the object to set custom name for + * @param name the the custom name to set + */ + void setObjectName( const VObject *obj, const QString name ) { m_objectNames.insert( obj, name ); } + + bool saveAsPath() const { return m_saveAsPath; } + void saveAsPath( bool b ) { m_saveAsPath = b; } + + /** + * Returns the document's grid. + * + * @return the doument's grid + */ + KarbonGridData &grid() { return m_gridData; } + +private: + /** + * Document width. + */ + double m_width; + + /** + * Document height. + */ + double m_height; + + + /// The layers in this document. + VLayerList m_layers; + /// The active layer. + VLayer* m_activeLayer; + + /// The selection. A list of selected objects. + VSelection* m_selection; + /// The selectionMode + VSelectionMode m_selectionMode; + + /** + * The unit. + */ + KoUnit::Unit m_unit; + + QMap<const VObject *, QString> m_objectNames; + + // TODO this flag is used nowhere, can we remove it? + bool m_saveAsPath; + + KarbonGridData m_gridData; +}; + +#endif + diff --git a/karbon/core/vfill.cc b/karbon/core/vfill.cc new file mode 100644 index 00000000..44f69f75 --- /dev/null +++ b/karbon/core/vfill.cc @@ -0,0 +1,181 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> +#include <kdebug.h> + +#include <KoGenStyles.h> +#include <KoOasisLoadingContext.h> +#include <KoOasisStyles.h> +#include <KoXmlNS.h> + +#include "vfill.h" + +VFill::VFill() + : m_type( none ) +{ + /*m_gradient.addStop( VColor( Qt::red.rgb() ), 0.0 ); + m_gradient.addStop( VColor( Qt::yellow.rgb() ), 1.0 ); + m_gradient.setOrigin( KoPoint( 0, 0 ) ); + m_gradient.setVector( KoPoint( 0, 50 ) ); + m_gradient.setSpreadMethod( gradient_spread_reflect );*/ + //kdDebug(38000) << "Size of VFill : " << sizeof(*this) << endl; +} + +VFill::VFill( const VColor &c ) + : m_type( solid ) +{ + m_color = c; + //kdDebug(38000) << "Size of VFill : " << sizeof(*this) << endl; +} + +VFill::VFill( const VFill& fill ) +{ + // doesn't copy parent: + *this = fill; +} + +void +VFill::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "FILL" ); + element.appendChild( me ); + + if( !( m_type == none ) ) + { + // save color: + m_color.save( me ); + } + if( m_type == grad ) + { + // save gradient: + m_gradient.save( me ); + } + else if( m_type == patt ) + { + // save pattern: + m_pattern.save( me ); + } +} + +void +VFill::saveOasis( KoGenStyles &mainStyles, KoGenStyle &style ) const +{ + if( m_type == solid ) + { + style.addProperty( "draw:fill", "solid" ); + style.addProperty( "draw:fill-color", QColor( m_color ).name() ); + if( m_color.opacity() < 1 ) + style.addProperty( "draw:opacity", QString( "%1%" ).arg( m_color.opacity() * 100. ) ); + } + else if( m_type == grad ) + { + style.addProperty( "draw:fill", "gradient" ); + QString grad = m_gradient.saveOasis( mainStyles ); + style.addProperty( "draw:fill-gradient-name", grad ); + if( m_color.opacity() < 1 ) + style.addProperty( "draw:opacity", QString( "%1%" ).arg( m_color.opacity() * 100. ) ); + } + else if( m_type == patt ) + style.addProperty( "draw:fill", "hatch" ); + else + style.addProperty( "draw:fill", "none" ); +} + +void +VFill::loadOasis( const QDomElement &/*object*/, KoOasisLoadingContext &context, VObject* parent ) +{ + KoStyleStack &stack = context.styleStack(); + if( stack.hasAttributeNS( KoXmlNS::draw, "fill" ) ) + { + if( stack.attributeNS( KoXmlNS::draw, "fill" ) == "solid" ) + { + setType( VFill::solid ); + setColor( QColor( stack.attributeNS( KoXmlNS::draw, "fill-color" ) ) ); + } + else if( stack.attributeNS( KoXmlNS::draw, "fill" ) == "gradient" ) + { + setType( VFill::grad ); + QString style = stack.attributeNS( KoXmlNS::draw, "fill-gradient-name" ); + kdDebug()<<" style gradient name :"<<style<<endl; + QDomElement *grad = context.oasisStyles().drawStyles()[ style ]; + kdDebug()<<" style gradient name :"<< grad <<endl; + if( grad ) + m_gradient.loadOasis( *grad, stack, parent ); + } + if( stack.hasAttributeNS( KoXmlNS::draw, "opacity" ) ) + m_color.setOpacity( stack.attributeNS( KoXmlNS::draw, "opacity" ).remove( '%' ).toFloat() / 100. ); + } +} + +void +VFill::load( const QDomElement& element ) +{ + m_type = none; + + // load color: + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + if( e.tagName() == "COLOR" ) + { + m_type = solid; + m_color.load( e ); + } + if( e.tagName() == "GRADIENT" ) + { + m_type = grad; + m_gradient.load( e ); + } + else if( e.tagName() == "PATTERN" ) + { + m_type = patt; + m_pattern.load( e ); + } + } + } +} + +VFill& +VFill::operator=( const VFill& fill ) +{ + if( this != &fill ) + { + // dont copy the parent! + m_type = fill.m_type; + m_color = fill.m_color; + m_gradient = fill.m_gradient; + m_pattern = fill.m_pattern; + } + + return *this; +} + +void +VFill::transform( const QWMatrix& m ) +{ + if( type() == VFill::grad ) + gradient().transform( m ); + else if( type() == VFill::patt ) + pattern().transform( m ); +} diff --git a/karbon/core/vfill.h b/karbon/core/vfill.h new file mode 100644 index 00000000..67a31722 --- /dev/null +++ b/karbon/core/vfill.h @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VFILL_H__ +#define __VFILL_H__ + +#include "vcolor.h" +#include "vgradient.h" +#include "vpattern.h" +#include <koffice_export.h> + +class QDomElement; +class KoGenStyle; +class KoGenStyles; +class KoOasisLoadingContext; + + +/** + * Manages the fill of shapes. + * + * The fill can be solid or gradient. + * Also two fill rules are supported that effect how the shape is + * filled. For explanation see the QPainter documentation. + * + * Default is no fill and even-odd filling rule. + */ +class KARBONBASE_EXPORT VFill +{ +public: + enum VFillType + { + none = 0, /// no fill at all + solid = 1, /// solid fill + grad = 2, /// gradient fill + patt = 3, /// pattern fill + unknown = 4 + }; + + VFill(); + VFill( const VColor & ); + VFill( const VFill & ); + + const VColor& color() const { return m_color; } + void setColor( const VColor& color, bool bsolid = true ) { m_color = color; if( bsolid ) m_type = solid; } + + VGradient& gradient() { return m_gradient; } + const VGradient& gradient() const { return m_gradient; } + + VPattern& pattern() { return m_pattern; } + const VPattern& pattern() const { return m_pattern; } + + VFillType type() const { return m_type; } + void setType( VFillType type ) { m_type = type; } + + void save( QDomElement& element ) const; + void saveOasis( KoGenStyles &mainStyles, KoGenStyle &style ) const; + void load( const QDomElement& element ); + void loadOasis( const QDomElement &object, KoOasisLoadingContext &context, VObject* parent = 0L ); + + VFill& operator=( const VFill& fill ); + + void transform( const QWMatrix& m ); + +private: + VColor m_color; + VGradient m_gradient; + VPattern m_pattern; + + VFillType m_type : 3; +}; + +#endif + diff --git a/karbon/core/vfillrule.h b/karbon/core/vfillrule.h new file mode 100644 index 00000000..e6af3606 --- /dev/null +++ b/karbon/core/vfillrule.h @@ -0,0 +1,31 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VFILLRULE_H__ +#define __VFILLRULE_H__ + +enum VFillRule +{ + evenOdd = 0, + winding = 1 +}; + +#endif + diff --git a/karbon/core/vglobal.cc b/karbon/core/vglobal.cc new file mode 100644 index 00000000..b118e5e2 --- /dev/null +++ b/karbon/core/vglobal.cc @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <math.h> + +#include "vglobal.h" + + +int +VGlobal::binomialCoeff( unsigned n, unsigned k ) +{ + return + static_cast<int>( + 0.5 + + exp( + factorialLn( n ) - + factorialLn( k ) - + factorialLn( n - k ) ) ); +} + +double +VGlobal::factorialLn( unsigned n ) +{ + const unsigned cacheSize = 100; + + // A static array is initalized to zero. + static double cache[ cacheSize ]; + + + if( n <= 1 ) + return 0.0; + + if( n <= cacheSize - 1 ) + { + return cache[ n ] + ? cache[ n ] + : ( cache[ n ] = gammaLn( n + 1.0 ) ); + } + else + { + return gammaLn( n + 1.0 ); + } +} + +double +VGlobal::gammaLn( double x ) +{ + static double coeff[ 6 ] = + { + 76.18009172947146, + -86.50532032941677, + 24.01409824083091, + -1.231739572450155, + 0.1208650973866179e-2, + -0.5395239384953e-5 + }; + + double y = x; + + double tmp = x + 5.5; + tmp -= ( x + 0.5 ) * log( tmp ); + + double ser = 1.000000000190015; + + for( int i = 0; i < 5; ++i ) + { + ser += coeff[ i ] / ++y; + } + + return -tmp + log( 2.5066282746310005 * ser / x ); +} + diff --git a/karbon/core/vglobal.h b/karbon/core/vglobal.h new file mode 100644 index 00000000..c20d48b0 --- /dev/null +++ b/karbon/core/vglobal.h @@ -0,0 +1,109 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGLOBAL_H__ +#define __VGLOBAL_H__ + +#include <kglobal.h> + +// define some often used mathematical constants et al: + +// TODO: optimize those values. + +namespace VGlobal +{ + const double pi = 3.14159265358979323846; // pi + const double twopi = 6.28318530717958647692; // 2pi + const double pi_2 = 1.57079632679489661923; // pi/2 + const double pi_180 = 0.01745329251994329576; // pi/180 + const double one_pi_180 = 57.29577951308232087684; // 180/pi + const double sqrt2 = 1.41421356237309504880; // sqrt(2) + const double one_3 = 0.33333333333333333333; // 1/3 + const double two_3 = 0.66666666666666666667; // 2/3 + const double one_6 = 0.16666666666666666667; // 1/6 + const double one_7 = 0.14285714285714285714; // 1/7 + + /** + * Constants used to decide if a number is equal zero or nearly the same + * as another number. + */ + const double veryBigNumber = 1.0e8; + const double verySmallNumber = 1.0e-8; + + /** + * A bezier with this flatness is considered "flat". Used in subdividing. + */ + const double flatnessTolerance = 0.01; + + /** + * A tolerance used to approximate bezier lengths. If the relative difference + * between chordlength and polylength (length of the controlpolygon) is smaller + * than this value, the length of the bezier is 1/2 chordlength + 1/2 polylength. + */ + const double lengthTolerance = 0.005; + + /** + * A tolerance used to calculate param t on a segment at a given arc + * length (counting from t=0). + * If the relative difference between a length approximation and the given + * length is smaller than this value, they are assumed to be identical. + */ + const double paramLengthTolerance = 0.001; + + /** + * A range for KoPoint::isNear() check, to decide if a KoPoint "is the same" + * as another. + */ + const double isNearRange = 0.001; + + /** + * A tolerance for multiplying normalized (length=1) vectors. A result of + * >= parallelTolerance indicates parallel vectors. + */ + const double parallelTolerance = 0.99; + + /** + * Returns the sign of paramater a. + */ + inline int sign( double a ) + { + return a < 0.0 + ? -1 + : 1; + } + + /** + * Calculates the binomial coefficient n! / ( k! * ( n - k)! ). + */ + int binomialCoeff( unsigned n, unsigned k ); + + /** + * Calculates the value ln( n! ). + */ + double factorialLn( unsigned n ); + + /** + * Calculates the value ln| Gamma(x) | for x > 0. + */ + double gammaLn( double x ); +} + +#endif + diff --git a/karbon/core/vgradient.cc b/karbon/core/vgradient.cc new file mode 100644 index 00000000..cd3b55b6 --- /dev/null +++ b/karbon/core/vgradient.cc @@ -0,0 +1,370 @@ +/* This file is part of the KDE project + Copyright (C) 2002 - 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> +#include <qbuffer.h> + +#include "vdocument.h" +#include "vglobal.h" +#include "vgradient.h" + +#include <KoGenStyles.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> + +int VGradient::VColorStopList::compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ) +{ + float r1 = ( (VColorStop*)item1 )->rampPoint; + float r2 = ( (VColorStop*)item2 )->rampPoint; + + return ( r1 == r2 ? 0 : r1 < r2 ? -1 : 1 ); +} // VGradient::VColorStopList::compareItems + +VGradient::VGradient( VGradientType type ) + : m_type( type ) +{ + m_colorStops.setAutoDelete( true ); + + // set up dummy gradient + VColor color; + + color.set( 1.0, 0.0, 0.0 ); + addStop( color, 0.0, 0.5 ); + + color.set( 1.0, 1.0, 0.0 ); + addStop( color, 1.0, 0.5 ); + + setOrigin( KoPoint( 0, 0 ) ); + setVector( KoPoint( 0, 50 ) ); + setRepeatMethod( VGradient::reflect ); +} + +VGradient::VGradient( const VGradient& gradient ) +{ + m_colorStops.setAutoDelete( true ); + + m_origin = gradient.m_origin; + m_focalPoint = gradient.m_focalPoint; + m_vector = gradient.m_vector; + m_type = gradient.m_type; + m_repeatMethod = gradient.m_repeatMethod; + + m_colorStops.clear(); + QPtrVector<VColorStop> cs = gradient.colorStops(); + for( uint i = 0; i < cs.count(); i++ ) + m_colorStops.append( new VColorStop( *cs[i] ) ); + m_colorStops.sort(); +} // VGradient::VGradient + +VGradient& VGradient::operator=( const VGradient& gradient ) +{ + m_colorStops.setAutoDelete( true ); + + if ( this == &gradient ) + return *this; + + m_origin = gradient.m_origin; + m_focalPoint = gradient.m_focalPoint; + m_vector = gradient.m_vector; + m_type = gradient.m_type; + m_repeatMethod = gradient.m_repeatMethod; + + m_colorStops.clear(); + QPtrVector<VColorStop> cs = gradient.colorStops(); + for( uint i = 0; i < cs.count(); i++ ) + m_colorStops.append( new VColorStop( *cs[i] ) ); + m_colorStops.sort(); + + return *this; +} // VGradient::operator= + +const QPtrVector<VColorStop> VGradient::colorStops() const +{ + QPtrVector<VColorStop> v; + m_colorStops.toVector( &v ); + v.setAutoDelete( false ); + return v; +} // VGradient::colorStops() + +void +VGradient::clearStops() +{ + m_colorStops.clear(); +} + +void +VGradient::addStop( const VColorStop& colorStop ) +{ + m_colorStops.inSort( new VColorStop( colorStop ) ); +} // VGradient::addStop + +void +VGradient::addStop( const VColor &color, float rampPoint, float midPoint ) +{ + // Clamping between 0.0 and 1.0 + rampPoint = kMax( 0.0f, rampPoint ); + rampPoint = kMin( 1.0f, rampPoint ); + // Clamping between 0.0 and 1.0 + midPoint = kMax( 0.0f, midPoint ); + midPoint = kMin( 1.0f, midPoint ); + + // Work around stops with the same position + VColorStop *v; + for(v = m_colorStops.first(); v; v = m_colorStops.next()) + { + if(rampPoint == v->rampPoint) + rampPoint += 0.001f; + } + m_colorStops.inSort( new VColorStop( rampPoint, midPoint, color ) ); +} + +void VGradient::removeStop( const VColorStop& colorstop ) +{ + m_colorStops.remove( &colorstop ); +} // VGradient::removeStop + +void +VGradient::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "GRADIENT" ); + + me.setAttribute( "originX", m_origin.x() ); + me.setAttribute( "originY", m_origin.y() ); + me.setAttribute( "focalX", m_focalPoint.x() ); + me.setAttribute( "focalY", m_focalPoint.y() ); + me.setAttribute( "vectorX", m_vector.x() ); + me.setAttribute( "vectorY", m_vector.y() ); + me.setAttribute( "type", m_type ); + me.setAttribute( "repeatMethod", m_repeatMethod ); + + // save stops + VColorStop* colorstop; + QPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops ); + for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() ) + { + QDomElement stop = element.ownerDocument().createElement( "COLORSTOP" ); + colorstop->color.save( stop ); + stop.setAttribute( "ramppoint", colorstop->rampPoint ); + stop.setAttribute( "midpoint", colorstop->midPoint ); + me.appendChild( stop ); + } + + element.appendChild( me ); +} + +QString +VGradient::saveOasis( KoGenStyles &mainStyles ) const +{ + bool radial = m_type == VGradient::radial; + KoGenStyle gradientStyle( radial ? VDocument::STYLE_RADIAL_GRADIENT : VDocument::STYLE_LINEAR_GRADIENT /*no family name*/); + if( radial ) + { + gradientStyle.addAttribute( "draw:style", "radial" ); + gradientStyle.addAttributePt( "svg:cx", m_origin.x() ); + gradientStyle.addAttributePt( "svg:cy", m_origin.y() ); + double dx = m_vector.x() - m_origin.x(); + double dy = m_vector.y() - m_origin.y(); + gradientStyle.addAttributePt( "svg:r", sqrt( dx * dx + dy * dy ) ); + gradientStyle.addAttributePt( "svg:fx", m_focalPoint.x() ); + gradientStyle.addAttributePt( "svg:fy", m_focalPoint.y() ); + } + else + { + gradientStyle.addAttribute( "draw:style", "linear" ); + gradientStyle.addAttributePt( "svg:x1", m_origin.x() ); + gradientStyle.addAttributePt( "svg:y1", m_origin.y() ); + gradientStyle.addAttributePt( "svg:x2", m_vector.x() ); + gradientStyle.addAttributePt( "svg:y2", m_vector.y() ); + } + if( m_repeatMethod == VGradient::repeat ) + gradientStyle.addAttribute( "svg:spreadMethod", "repeat" ); + else if( m_repeatMethod == VGradient::reflect ) + gradientStyle.addAttribute( "svg:spreadMethod", "reflect" ); + else + gradientStyle.addAttribute( "svg:spreadMethod", "pad" ); + QBuffer buffer; + buffer.open( IO_WriteOnly ); + KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level + + // save stops + VColorStop* colorstop; + QPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops ); + for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() ) + { + elementWriter.startElement( "svg:stop" ); + elementWriter.addAttribute( "svg:offset", QString( "%1" ).arg( colorstop->rampPoint ) ); + elementWriter.addAttribute( "svg:color", QColor( colorstop->color ).name() ); + if( colorstop->color.opacity() < 1 ) + elementWriter.addAttribute( "svg:stop-opacity", QString( "%1" ).arg( colorstop->color.opacity() ) ); + elementWriter.endElement(); + } + + QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() ); + gradientStyle.addChildElement( "svg:stop", elementContents ); + return mainStyles.lookup( gradientStyle, "gradient" ); +} + +void +VGradient::loadOasis( const QDomElement &object, KoStyleStack &/*stack*/, VObject* parent ) +{ + kdDebug(38000) << "namespaceURI: " << object.namespaceURI() << endl; + kdDebug(38000) << "localName: " << object.localName() << endl; + + KoRect bb; + + if( parent ) + bb = parent->boundingBox(); + + if( object.namespaceURI() == KoXmlNS::draw && object.localName() == "gradient" ) + { + m_repeatMethod = VGradient::reflect; + QString strType = object.attributeNS( KoXmlNS::draw, "style", QString::null ); + if( strType == "radial" ) + { + m_type = VGradient::radial; + // TODO : find out whether Oasis works with boundingBox only? + double cx = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cx", QString::null ).remove("%") ); + m_origin.setX( bb.bottomLeft().x() + bb.width() * 0.01 * cx ); + double cy = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cy", QString::null ).remove("%") ); + m_origin.setY( bb.bottomLeft().y() - bb.height() * 0.01 * cy ); + m_focalPoint = m_origin; + m_vector = bb.topRight(); + } + else if( strType == "linear" ) + { + m_type = VGradient::linear; + double angle = 90 + object.attributeNS( KoXmlNS::draw, "angle", "0" ).toDouble(); + double radius = 0.5 * sqrt( bb.width()*bb.width() + bb.height()*bb.height() ); + double sx = cos( angle * VGlobal::pi / 180 ) * radius; + double sy = sin( angle * VGlobal::pi / 180 ) * radius; + m_origin.setX( bb.center().x() + sx ); + m_origin.setY( bb.center().y() + sy ); + m_vector.setX( bb.center().x() - sx ); + m_vector.setY( bb.center().y() - sy ); + m_focalPoint = m_origin; + } + else return; + + VColor startColor( QColor( object.attributeNS( KoXmlNS::draw, "start-color", QString::null ) ) ); + VColor endColor( QColor( object.attributeNS( KoXmlNS::draw, "end-color", QString::null ) ) ); + + double startOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "start-intensity", "100" ).remove("%").toDouble(); + double endOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "end-intensity", "100" ).remove("%").toDouble(); + + startColor.setOpacity( startOpacity ); + endColor.setOpacity( endOpacity ); + m_colorStops.clear(); + addStop( startColor, 0.0, 0.5 ); + addStop( endColor, 1.0, 0.0 ); + m_colorStops.sort(); + + } + else if( object.namespaceURI() == KoXmlNS::svg ) + { + if( object.localName() == "linearGradient" ) + { + m_type = VGradient::linear; + m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x1", QString::null ) ) ); + m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y1", QString::null ) ) ); + m_vector.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x2", QString::null ) ) ); + m_vector.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y2", QString::null ) ) ); + m_focalPoint = m_origin; + } + else if( object.localName() == "radialGradient" ) + { + m_type = VGradient::radial; + m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) ); + m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) ); + double r = KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "r", QString::null ) ); + m_vector.setX( m_origin.x() + r ); + m_vector.setY( m_origin.y() ); + m_focalPoint.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fx", QString::null ) ) ); + m_focalPoint.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fy", QString::null ) ) ); + } + + QString strSpread( object.attributeNS( KoXmlNS::svg, "spreadMethod", "pad" ) ); + if( strSpread == "repeat" ) + m_repeatMethod = VGradient::repeat; + else if( strSpread == "reflect" ) + m_repeatMethod = VGradient::reflect; + else + m_repeatMethod = VGradient::none; + + m_colorStops.clear(); + + // load stops + QDomNodeList list = object.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement colorstop = list.item( i ).toElement(); + + if( colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop" ) + { + VColor color( QColor( colorstop.attributeNS( KoXmlNS::svg, "color", QString::null ) ) ); + color.setOpacity( colorstop.attributeNS( KoXmlNS::svg, "stop-opacity", "1.0" ).toDouble() ); + addStop( color, colorstop.attributeNS( KoXmlNS::svg, "offset", "0.0" ).toDouble(), 0.5 ); + } + } + } + m_colorStops.sort(); + } +} + +void +VGradient::load( const QDomElement& element ) +{ + m_origin.setX( element.attribute( "originX", "0.0" ).toDouble() ); + m_origin.setY( element.attribute( "originY", "0.0" ).toDouble() ); + m_focalPoint.setX( element.attribute( "focalX", "0.0" ).toDouble() ); + m_focalPoint.setY( element.attribute( "focalY", "0.0" ).toDouble() ); + m_vector.setX( element.attribute( "vectorX", "0.0" ).toDouble() ); + m_vector.setY( element.attribute( "vectorY", "0.0" ).toDouble() ); + m_type = (VGradientType)element.attribute( "type", 0 ).toInt(); + m_repeatMethod = (VGradientRepeatMethod)element.attribute( "repeatMethod", 0 ).toInt(); + + m_colorStops.clear(); + + // load stops + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement colorstop = list.item( i ).toElement(); + + if( colorstop.tagName() == "COLORSTOP" ) + { + VColor color; + color.load( colorstop.firstChild().toElement() ); + addStop( color, colorstop.attribute( "ramppoint", "0.0" ).toDouble(), colorstop.attribute( "midpoint", "0.5" ).toDouble() ); + } + } + } + m_colorStops.sort(); +} + +void +VGradient::transform( const QWMatrix &m ) +{ + m_origin = m_origin.transform( m ); + m_focalPoint = m_focalPoint.transform( m ); + m_vector = m_vector.transform( m ); +} diff --git a/karbon/core/vgradient.h b/karbon/core/vgradient.h new file mode 100644 index 00000000..5587af7e --- /dev/null +++ b/karbon/core/vgradient.h @@ -0,0 +1,129 @@ +/* This file is part of the KDE project + Copyright (C) 2002 - 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGRADIENT_H__ +#define __VGRADIENT_H__ + +#include <qptrlist.h> +#include <qptrvector.h> + +#include <koffice_export.h> +#include <KoPoint.h> + +#include "vcolor.h" + +class QDomElement; +class KoGenStyle; +class KoGenStyles; +class KoStyleStack; +class VObject; + +class VColorStop +{ + public: + VColorStop( double r, double m, VColor c ) + { rampPoint = r; midPoint = m; color = c; }; + VColorStop( const VColorStop& colorStop ) + { rampPoint = colorStop.rampPoint; midPoint = colorStop.midPoint; color = colorStop.color; }; + + VColor color; + + // relative position of color point (0.0-1.0): + float rampPoint; + + // relative position of midpoint (0.0-1.0) + // between two ramp points. ignored for last VColorStop. + float midPoint; + + friend inline bool operator== ( VColorStop& s1, VColorStop& s2 ) + { return s1.rampPoint == s2.rampPoint; }; +}; // VColorStop + +class KARBONBASE_EXPORT VGradient +{ +friend class VGradientWidget; + +public: + enum VGradientType + { + linear = 0, + radial = 1, + conic = 2 + }; + + enum VGradientRepeatMethod + { + none = 0, + reflect = 1, + repeat = 2 + }; + + class VColorStopList : public QPtrList<VColorStop> + { + protected: + virtual int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 ); + }; // VColorStopList + + VGradient( VGradientType type = linear ); + VGradient( const VGradient& gradient ); + + VGradient& operator=(const VGradient& gradient); + + VGradientType type() const { return m_type; } + void setType( VGradientType type ) { m_type = type; } + + VGradientRepeatMethod repeatMethod() const { return m_repeatMethod; } + void setRepeatMethod( VGradientRepeatMethod repeatMethod ) { m_repeatMethod = repeatMethod; } + + const QPtrVector<VColorStop> colorStops() const; + void addStop( const VColorStop& colorStop ); + void addStop( const VColor &color, float rampPoint, float midPoint ); + void removeStop( const VColorStop& colorStop ); + void clearStops(); + + KoPoint origin() const { return m_origin; } + void setOrigin( const KoPoint &origin ) { m_origin = origin; } + + KoPoint focalPoint() const { return m_focalPoint; } + void setFocalPoint( const KoPoint &focalPoint ) { m_focalPoint = focalPoint; } + + KoPoint vector() const { return m_vector; } + void setVector( const KoPoint &vector ) { m_vector = vector; } + + void save( QDomElement& element ) const; + QString saveOasis( KoGenStyles &mainStyles ) const; + void load( const QDomElement& element ); + void loadOasis( const QDomElement &object, KoStyleStack &stack, VObject* parent = 0L ); + + void transform( const QWMatrix& m ); + +protected: + VColorStopList m_colorStops; + +private: + VGradientType m_type : 2; + VGradientRepeatMethod m_repeatMethod : 2; + + // coordinates: + KoPoint m_origin; + KoPoint m_focalPoint; + KoPoint m_vector; +}; // VGradient + +#endif /* __VGRADIENT_H__ */ diff --git a/karbon/core/vgroup.cc b/karbon/core/vgroup.cc new file mode 100644 index 00000000..d356b2b1 --- /dev/null +++ b/karbon/core/vgroup.cc @@ -0,0 +1,398 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qdom.h> + +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoOasisLoadingContext.h> +#include <KoStyleStack.h> +#include <KoXmlNS.h> + +#include "vcomposite.h" +#include "shapes/vellipse.h" +#include "shapes/vrectangle.h" +#include "shapes/vsinus.h" +#include "shapes/vspiral.h" +#include "shapes/vstar.h" +#include "shapes/vpolyline.h" +#include "shapes/vpolygon.h" +#include "vfill.h" +#include "vgroup.h" +#include "vlayer.h" +#include "vimage.h" +#include "vstroke.h" +#include "vvisitor.h" +#include "vclipgroup.h" +#ifdef HAVE_KARBONTEXT +#include "vtext.h" +#endif + +#include <kdebug.h> + + +VGroup::VGroup( VObject* parent, VState state ) + : VObject( parent, state ) +{ + m_stroke = new VStroke( this ); + m_fill = new VFill(); +} + +VGroup::VGroup( const VGroup& group ) + : VObject( group ) +{ + m_stroke = new VStroke( *group.m_stroke ); + m_stroke->setParent( this ); + m_fill = new VFill( *group.m_fill ); + + VObjectListIterator itr = group.m_objects; + for ( ; itr.current() ; ++itr ) + append( itr.current()->clone() ); +} + +VGroup::~VGroup() +{ + VObjectListIterator itr = m_objects; + for ( ; itr.current(); ++itr ) + { + delete( itr.current() ); + } +} + +void +VGroup::draw( VPainter* painter, const KoRect* rect ) const +{ + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + VObjectListIterator itr = m_objects; + + for ( ; itr.current(); ++itr ) + itr.current()->draw( painter, rect ); +} + +const KoRect& +VGroup::boundingBox() const +{ + if( m_boundingBoxIsInvalid ) + { + // clear: + m_boundingBox = KoRect(); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + { + m_boundingBox |= itr.current()->boundingBox(); + } + + m_boundingBoxIsInvalid = false; + } + + return m_boundingBox; +} + +VGroup* +VGroup::clone() const +{ + return new VGroup( *this ); +} + +void +VGroup::setFill( const VFill& fill ) +{ + VObjectListIterator itr = m_objects; + + for ( ; itr.current() ; ++itr ) + itr.current()->setFill( fill ); + + VObject::setFill( fill ); +} + +void +VGroup::setStroke( const VStroke& stroke ) +{ + VObjectListIterator itr = m_objects; + + for ( ; itr.current() ; ++itr ) + itr.current()->setStroke( stroke ); + + VObject::setStroke( stroke ); +} + +void +VGroup::setState( const VState state ) +{ + VObjectListIterator itr = m_objects; + + for ( ; itr.current() ; ++itr ) + if( m_state == VObject::deleted || itr.current()->state() != VObject::deleted ) + itr.current()->setState( state ); + + VObject::setState( state ); +} + +void +VGroup::save( QDomElement& element ) const +{ + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "GROUP" ); + element.appendChild( me ); + + // save objects: + VObjectListIterator itr = m_objects; + + for ( ; itr.current(); ++itr ) + itr.current()->save( me ); + + VObject::save( me ); + } +} + +void +VGroup::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + docWriter->startElement( "draw:g" ); + + // save objects: + VObjectListIterator itr = m_objects; + + for ( ; itr.current(); ++itr ) + itr.current()->saveOasis( store, docWriter, mainStyles, ++index ); + + docWriter->endElement(); +} + +bool +VGroup::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + m_objects.setAutoDelete( true ); + m_objects.clear(); + m_objects.setAutoDelete( false ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + + kdDebug(38000) << "VGroup::loadOasis: e.tagName() = " << e.tagName() << endl; + kdDebug(38000) << "VGroup::loadOasis: e.namespaceURI() = " << e.namespaceURI() << endl; + kdDebug(38000) << "VGroup::loadOasis: e.localName() = " << e.localName() << endl; + + if( e.namespaceURI() != KoXmlNS::draw ) + continue; + + context.styleStack().save(); + + if( e.localName() == "path" || e.localName() == "custom-shape" ) + { + VPath* composite = new VPath( this ); + composite->loadOasis( e, context ); + append( composite ); + } + else if( e.localName() == "circle" || e.localName() == "ellipse" ) + { + VEllipse* ellipse = new VEllipse( this ); + ellipse->loadOasis( e, context ); + append( ellipse ); + } + else if( e.localName() == "rect" ) + { + VRectangle* rectangle = new VRectangle( this ); + rectangle->loadOasis( e, context ); + append( rectangle ); + } + else if( e.localName() == "g" ) + { + VGroup* group = new VGroup( this ); + group->loadOasis( e, context ); + append( group ); + } + else if( e.localName() == "polyline" || e.localName() == "line" ) + { + VPolyline* polyline = new VPolyline( this ); + polyline->loadOasis( e, context ); + append( polyline ); + } + else if( e.localName() == "polygon" ) + { + VPolygon* polygon = new VPolygon( this ); + polygon->loadOasis( e, context ); + append( polygon ); + } + + context.styleStack().restore(); + } + } + + return true; +} + +void +VGroup::load( const QDomElement& element ) +{ + m_objects.setAutoDelete( true ); + m_objects.clear(); + m_objects.setAutoDelete( false ); + + VObject::load( element ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + + if( e.tagName() == "COMPOSITE" || e.tagName() == "PATH" ) // TODO : remove COMPOSITE later + { + VPath* composite = new VPath( this ); + composite->load( e ); + append( composite ); + } + else if( e.tagName() == "ELLIPSE" ) + { + VEllipse* ellipse = new VEllipse( this ); + ellipse->load( e ); + append( ellipse ); + } + else if( e.tagName() == "RECT" ) + { + VRectangle* rectangle = new VRectangle( this ); + rectangle->load( e ); + append( rectangle ); + } + else if( e.tagName() == "POLYLINE" ) + { + VPolyline* polyline = new VPolyline( this ); + polyline->load( e ); + append( polyline ); + } + else if( e.tagName() == "POLYGON" ) + { + VPolygon* polygon = new VPolygon( this ); + polygon->load( e ); + append( polygon ); + } + else if( e.tagName() == "SINUS" ) + { + VSinus* sinus = new VSinus( this ); + sinus->load( e ); + append( sinus ); + } + else if( e.tagName() == "SPIRAL" ) + { + VSpiral* spiral = new VSpiral( this ); + spiral->load( e ); + append( spiral ); + } + else if( e.tagName() == "STAR" ) + { + VStar* star = new VStar( this ); + star->load( e ); + append( star ); + } + else if( e.tagName() == "GROUP" ) + { + VGroup* group = new VGroup( this ); + group->load( e ); + append( group ); + } + else if( e.tagName() == "CLIP" ) + { + VClipGroup* grp = new VClipGroup( this ); + grp->load( e ); + append( grp ); + } + else if( e.tagName() == "IMAGE" ) + { + VImage* img = new VImage( this ); + img->load( e ); + append( img ); + } + else if( e.tagName() == "TEXT" ) + { +#ifdef HAVE_KARBONTEXT + VText *text = new VText( this ); + text->load( e ); + append( text ); +#endif + } + } + } +} + +void +VGroup::accept( VVisitor& visitor ) +{ + visitor.visitVGroup( *this ); +} + + +void +VGroup::take( const VObject& object ) +{ + m_objects.removeRef( &object ); + + invalidateBoundingBox(); +} + +void +VGroup::append( VObject* object ) +{ + object->setParent( this ); + + m_objects.append( object ); + + invalidateBoundingBox(); +} + +void +VGroup::insertInfrontOf( VObject* newObject, VObject* oldObject ) +{ + newObject->setParent( this ); + + m_objects.insert( m_objects.find( oldObject ), newObject ); + + invalidateBoundingBox(); +} + +void +VGroup::clear() +{ + m_objects.clear(); + + invalidateBoundingBox(); +} + diff --git a/karbon/core/vgroup.h b/karbon/core/vgroup.h new file mode 100644 index 00000000..25190178 --- /dev/null +++ b/karbon/core/vgroup.h @@ -0,0 +1,117 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGROUP_H__ +#define __VGROUP_H__ + +#include <qptrlist.h> + +#include "vobject.h" +#include <koffice_export.h> +typedef QPtrList<VObject> VObjectList; +typedef QPtrListIterator<VObject> VObjectListIterator; + +/** + * Base class for all sort of VObject conglomerats. + */ + +class KARBONBASE_EXPORT VGroup : public VObject +{ +public: + /** + * Constructs a new group object that is child of parent and has the given state. + * + * The object's fill and stroke are created here. + * + * @param parent the new object's parent + * @param state the new object's state + */ + VGroup( VObject* parent, VState state = normal ); + + /** + * Copy constructor. + * + * @param group the group to copy properties from + */ + VGroup( const VGroup& group ); + + /** + * Destroys the group and all of the child objects. + */ + virtual ~VGroup(); + + virtual void draw( VPainter* painter, const KoRect* rect = 0L ) const; + + virtual const KoRect& boundingBox() const; + + virtual void setStroke( const VStroke& stroke ); + virtual void setFill( const VFill& fill ); + + virtual void setState( const VState state ); + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VGroup* clone() const; + + virtual void accept( VVisitor& visitor ); + + /** + * Removes the reference to child object, not the object itself. + * + * @param object the child object to remove + */ + void take( const VObject& object ); + + /** + * Appends a new child object. + * + * @param object the object to append + */ + void append( VObject* object ); + + /** + * This function is important for undo/redo. It inserts newObject in front + * of oldObject. + * + * @param newObject the new object to insert + * @param oldObject the old object the new object is inserted in front of + */ + virtual void insertInfrontOf( VObject* newObject, VObject* oldObject ); + + /** + * Clears the group, without destroying the grouped objects. + */ + void clear(); + + /** + * Read only access to the grouped objects. + * + * @return reference to the list of grouped objects + */ + const VObjectList& objects() const { return m_objects; } + +protected: + VObjectList m_objects; /**< the list of grouped objects */ +}; + +#endif + diff --git a/karbon/core/vgroup_iface.cc b/karbon/core/vgroup_iface.cc new file mode 100644 index 00000000..fec75358 --- /dev/null +++ b/karbon/core/vgroup_iface.cc @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <kapplication.h> +#include <dcopclient.h> + +#include "vgroup_iface.h" +#include "vgroup.h" + +VGroupIface::VGroupIface( VGroup *group ) + : VObjectIface( group ), m_group( group ) +{ +} + +void +VGroupIface::clear() +{ + m_group->clear(); +} + +QValueList<DCOPRef> +VGroupIface::objects() +{ + QValueList<DCOPRef> lst; + VObjectListIterator itr = m_group->objects(); + for( ; itr.current(); ++itr ) + lst.append( DCOPRef( kapp->dcopClient()->appId(), itr.current()->dcopObject()->objId() ) ); + return lst; +} + diff --git a/karbon/core/vgroup_iface.h b/karbon/core/vgroup_iface.h new file mode 100644 index 00000000..c189a7a1 --- /dev/null +++ b/karbon/core/vgroup_iface.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGROUP_IFACE_H__ +#define __VGROUP_IFACE_H__ + +#include <qvaluelist.h> + +#include "vobject_iface.h" + +class VGroup; + +//typedef QPtrList<VObject> VObjectList; +//typedef QPtrListIterator<VObject> VObjectListIterator; + +class VGroupIface : public VObjectIface +{ + K_DCOP + +public: + VGroupIface( VGroup *group ); + +k_dcop: + //void take( const VObject& object ); + + //void append( DCOPRef object ); + + //virtual void insertInfrontOf( VObject* newObject, VObject* oldObject ); + + void clear(); + QValueList<DCOPRef> objects(); + +private: + VGroup *m_group; +}; + +#endif + diff --git a/karbon/core/vimage.cc b/karbon/core/vimage.cc new file mode 100644 index 00000000..a8bbf138 --- /dev/null +++ b/karbon/core/vimage.cc @@ -0,0 +1,158 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers +*/ + +#include "vimage.h" +#include "vpainter.h" +#include "vvisitor.h" +#include "vpath.h" +#include "vfill.h" +#include "vstroke.h" + +#include <qdom.h> +#include <qimage.h> +#include <KoRect.h> + +#include <render/vqpainter.h> + +#include <kdebug.h> + +VImage::VImage( VObject *parent, const QString &fname ) : VObject( parent ), m_image( 0L ), m_fname( fname ) +{ + m_stroke = new VStroke( this ); + m_stroke->setType( VStroke::none ); + m_fill = new VFill(); + m_image = new QImage( m_fname ); + if( m_image->depth() != 32 ) + *m_image = m_image->convertDepth( 32 ); + m_image->setAlphaBuffer( true ); + *m_image = m_image->swapRGB(); + *m_image = m_image->mirror( false, true ); +} + +VImage::VImage( const VImage &other ) : VObject( other ) +{ + if( other.m_image ) + m_image = new QImage( *other.m_image ); + else + m_image = 0L; + + if ( other.stroke() ) + setStroke( *other.stroke() ); + if ( other.fill() ) + setFill( *other.fill() ); + + m_fname = other.m_fname; + m_boundingBox = other.m_boundingBox; + m_matrix = other.m_matrix; +} + +VImage::~VImage() +{ + delete m_image; +} + +void +VImage::draw( VPainter *painter, const KoRect * ) const +{ + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + if( state() == edit ) + { + KoRect bbox = KoRect( 0, 0, m_image->width(), m_image->height() ); + KoPoint tl = bbox.topLeft().transform( m_matrix ); + KoPoint tr = bbox.topRight().transform( m_matrix ); + KoPoint bl = bbox.bottomLeft().transform( m_matrix ); + KoPoint br = bbox.bottomRight().transform( m_matrix ); + + painter->moveTo( tl ); + painter->lineTo( tr ); + painter->lineTo( br ); + painter->lineTo( bl ); + painter->lineTo( tl ); + + painter->setRasterOp( Qt::XorROP ); + //painter->setPen( stroke() ); + painter->setPen( Qt::yellow ); + painter->setBrush( Qt::NoBrush ); + painter->strokePath(); + return; + } + + //painter->setWorldMatrix( m_matrix ); + + //*m_image = m_image->smoothScale( m_image->width() * zoomFactor, m_image->height() * zoomFactor, QImage::ScaleMin ); + m_boundingBox = KoRect( 0, 0, m_image->width(), m_image->height() ); + m_boundingBox = m_boundingBox.transform( m_matrix ); + if( !m_image->isNull() ) + painter->drawImage( *m_image, m_matrix ); +} + +void +VImage::transform( const QWMatrix& m ) +{ + //QWMatrix m2 = m; + //m_matrix *= m2.scale( 1.0, -1.0 ); + m_matrix *= m; + kdDebug(38000) << "dx : " << m.dx() << ", dy : " << m.dy() << endl; + m_boundingBox = m_boundingBox.transform( m ); +} + +VObject * +VImage::clone() const +{ + return new VImage( *this ); +} + +void +VImage::save( QDomElement& element ) const +{ + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "IMAGE" ); + element.appendChild( me ); + + me.setAttribute( "fname", m_fname ); + me.setAttribute( "m11", m_matrix.m11() ); + me.setAttribute( "m12", m_matrix.m12() ); + me.setAttribute( "m21", m_matrix.m21() ); + me.setAttribute( "m22", m_matrix.m22() ); + me.setAttribute( "dx", m_matrix.dx() ); + me.setAttribute( "dy", m_matrix.dy() ); + } +} + +void +VImage::load( const QDomElement& element ) +{ + setState( normal ); + m_fname = element.attribute( "fname" ); + m_matrix.setMatrix( element.attribute( "m11", "1.0" ).toDouble(), + element.attribute( "m12", "0.0" ).toDouble(), + element.attribute( "m21", "0.0" ).toDouble(), + element.attribute( "m22", "1.0" ).toDouble(), + element.attribute( "dx", "0.0" ).toDouble(), + element.attribute( "dy", "0.0" ).toDouble() ); + kdDebug(38000) << "VImage::load : " << m_fname.latin1() << endl; + delete m_image; + m_image = new QImage( m_fname ); + if( m_image->depth() != 32 ) + *m_image = m_image->convertDepth( 32 ); + m_image->setAlphaBuffer( true ); + *m_image = m_image->swapRGB(); + *m_image = m_image->mirror( false, true ); + m_boundingBox = KoRect( 0, 0, m_image->width(), m_image->height() ); +} + +void +VImage::accept( VVisitor& visitor ) +{ + visitor.visitVImage( *this ); +} + diff --git a/karbon/core/vimage.h b/karbon/core/vimage.h new file mode 100644 index 00000000..d73e4ee7 --- /dev/null +++ b/karbon/core/vimage.h @@ -0,0 +1,37 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers +*/ + +#ifndef __VIMAGE_H__ +#define __VIMAGE_H__ + +#include "vobject.h" +#include <koffice_export.h> +class QImage; + +// all vobjects exist inside a layer. + +class KARBONBASE_EXPORT VImage : public VObject +{ +public: + VImage( VObject *parent, const QString &fname = "" ); + VImage( const VImage & ); + virtual ~VImage(); + + virtual void draw( VPainter *painter, const KoRect *rect ) const; + + virtual void transform( const QWMatrix& m ); + virtual VObject* clone() const; + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + + virtual void accept( VVisitor& visitor ); + +private: + QImage *m_image; + QString m_fname; + QWMatrix m_matrix; +}; + +#endif diff --git a/karbon/core/vkarbonplugin.cc b/karbon/core/vkarbonplugin.cc new file mode 100644 index 00000000..94f38fe5 --- /dev/null +++ b/karbon/core/vkarbonplugin.cc @@ -0,0 +1,25 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vkarbonplugin.h" + +VKarbonPlugin::VKarbonPlugin( QObject *parent, const char* name ) : Plugin( parent, name ) +{ +} + diff --git a/karbon/core/vkarbonplugin.h b/karbon/core/vkarbonplugin.h new file mode 100644 index 00000000..39563829 --- /dev/null +++ b/karbon/core/vkarbonplugin.h @@ -0,0 +1,34 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VKARBONPLUGIN_H__ +#define __VKARBONPLUGIN_H__ + +#include <kparts/plugin.h> +#include <koffice_export.h> + +class KARBONBASE_EXPORT VKarbonPlugin : public KParts::Plugin +{ +public: + VKarbonPlugin( QObject *parent, const char* name ); + virtual ~VKarbonPlugin() {} +}; + +#endif + diff --git a/karbon/core/vlayer.cc b/karbon/core/vlayer.cc new file mode 100644 index 00000000..f74a3d4b --- /dev/null +++ b/karbon/core/vlayer.cc @@ -0,0 +1,186 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include <klocale.h> +#include <KoRect.h> + +#include "vcomposite.h" +#include "vdocument.h" +#include "vgroup.h" +#include "vlayer.h" +#include "vobject.h" +#include "vtext.h" +#include "vvisitor.h" +#include "vlayer_iface.h" +#include <kdebug.h> +#include "vclipgroup.h" +#include "vfill.h" +#include "vstroke.h" + +VLayer::VLayer( VObject* parent, VState state ) + : VGroup( parent, state ) +{ + setName( "Layer" ); + // HACK : vlayer just shouldn't have fill/stroke at all + delete m_fill; + m_fill = 0L; + delete m_stroke; + m_stroke = 0L; +} + +VLayer::VLayer( const VLayer& layer ) + : VGroup( layer ) +{ +} + +VLayer::~VLayer() +{ +} + +DCOPObject* VLayer::dcopObject() +{ + if ( !m_dcop ) + m_dcop = new VLayerIface( this ); + + return m_dcop; +} + +void +VLayer::draw( VPainter* painter, const KoRect* rect ) const +{ + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + VObjectListIterator itr = m_objects; + + for ( ; itr.current(); ++itr ) + itr.current()->draw( painter, rect ); +} + +void +VLayer::bringToFront( const VObject& object ) +{ + if( m_objects.getLast() == &object ) return; + + m_objects.remove( &object ); + + m_objects.append( &object ); +} + +void +VLayer::upwards( const VObject& object ) +{ + if( m_objects.getLast() == &object ) return; + + m_objects.remove( &object ); + + if( m_objects.current() != m_objects.getLast() ) + { + m_objects.next(); + m_objects.insert( m_objects.at(), &object ); + } + else + m_objects.append( &object ); +} + +void +VLayer::downwards( const VObject& object ) +{ + if( m_objects.getFirst() == &object ) return; + + int index = m_objects.find( &object ); + bool bLast = m_objects.getLast() == &object; + m_objects.remove( index ); + + if( !bLast ) m_objects.prev(); + + m_objects.insert( m_objects.at(), &object ); +} + +void +VLayer::sendToBack( const VObject& object ) +{ + if( m_objects.getFirst() == &object ) return; + + m_objects.remove( &object ); + + m_objects.prepend( &object ); +} + +void +VLayer::save( QDomElement& element ) const +{ + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "LAYER" ); + element.appendChild( me ); + + if( state() == normal || state() == normal_locked || state() == VObject::selected ) + me.setAttribute( "visible", 1 ); + + // save objects: + VObjectListIterator itr = m_objects; + for ( ; itr.current(); ++itr ) + itr.current()->save( me ); + + VObject::save( me ); + } +} + +void +VLayer::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + // save objects: + VObjectListIterator itr = m_objects; + + for ( ; itr.current(); ++itr ) + itr.current()->saveOasis( store, docWriter, mainStyles, ++index ); +} + +void +VLayer::load( const QDomElement& element ) +{ + setState( element.attribute( "visible" ) == 0 ? hidden : normal ); + VGroup::load( element ); +} + + +VLayer* +VLayer::clone() const +{ + return new VLayer( *this ); +} + +void +VLayer::accept( VVisitor& visitor ) +{ + visitor.visitVLayer( *this ); +} + diff --git a/karbon/core/vlayer.h b/karbon/core/vlayer.h new file mode 100644 index 00000000..26524416 --- /dev/null +++ b/karbon/core/vlayer.h @@ -0,0 +1,119 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VLAYER_H__ +#define __VLAYER_H__ + +#include "vgroup.h" +#include <koffice_export.h> +class QDomElement; +class DCOPObject; + + +/** + * VLayer manages a set of vobjects. It keeps the objects from bottom to top + * in a list, ie. objects higher in the list are drawn above lower objects. + * Objects in a layer can be manipulated and worked on independant of objects + * in other layers. + */ + +class KARBONBASE_EXPORT VLayer : public VGroup +{ +public: + /** + * Constructs a new layer object that is child of parent and has the given state. + * + * @param parent the new object's parent + * @param state the new object's state + */ + VLayer( VObject* parent, VState state = normal ); + + /** + * Copy constructor. + * + * @param layer the layer to copy properties from + */ + VLayer( const VLayer& layer ); + + virtual ~VLayer(); + virtual DCOPObject* dcopObject(); + + virtual void draw( VPainter *painter, const KoRect* rect = 0L ) const; + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + + virtual VLayer* clone() const; + + virtual void accept( VVisitor& visitor ); + + /** + * Moves the object to the top of the list. + * + * When the object is at the top this method has no effect. + * + * @param object the object to move + */ + void bringToFront( const VObject& object ); + + /** + * Moves the object one step up the list. + * + * When the object is at the top this method has no effect. + * + * @param object the object to move + */ + void upwards( const VObject& object ); + + /** + * Moves the object one step down the list. + * + * When the object is at the bottom this method has no effect. + * + * @param object the object to move + */ + void downwards( const VObject& object ); + + /** + * Moves the object to the end of the list. + * + * When the object is at the bottom this method has no effect. + * + * @param object the object to move + */ + void sendToBack( const VObject& object ); + + /** + * Selects or unselects the layer + * + * @param state the new selection state + */ + void setSelected( bool state ) { setState( state ? VObject::selected : VObject::normal ); } + + /** + * Returns the selection state of the layer + * + * @return the actual selection state + */ + bool selected() { return state() == VObject::selected; } +}; + +#endif + diff --git a/karbon/core/vlayer_iface.cc b/karbon/core/vlayer_iface.cc new file mode 100644 index 00000000..7db8a20b --- /dev/null +++ b/karbon/core/vlayer_iface.cc @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <dcopclient.h> + +#include "vlayer.h" +#include "vlayer_iface.h" + + +VLayerIface::VLayerIface( VLayer* layer ) + : VGroupIface( layer ), m_layer( layer ) +{ +} + +void +VLayerIface::setName( const QString& name ) +{ + m_layer->setName( name ); +} + +QString +VLayerIface::name() const +{ + return m_layer->name(); +} + +void +VLayerIface::setSelected( bool state ) +{ + m_layer->setSelected( state ); +} + +bool +VLayerIface::selected() const +{ + return m_layer->selected(); +} + diff --git a/karbon/core/vlayer_iface.h b/karbon/core/vlayer_iface.h new file mode 100644 index 00000000..9f34a4e0 --- /dev/null +++ b/karbon/core/vlayer_iface.h @@ -0,0 +1,47 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VLAYER_IFACE_H__ +#define __VLAYER_IFACE_H__ + +#include "vgroup_iface.h" +#include <qstring.h> + +class VLayer; + +class VLayerIface : public VGroupIface +{ + K_DCOP + +public: + VLayerIface( VLayer* layer ); + +k_dcop: + void setName( const QString& name ); + QString name() const; + + void setSelected( bool state ); + bool selected() const; + +private: + VLayer* m_layer; +}; + +#endif + diff --git a/karbon/core/vobject.cc b/karbon/core/vobject.cc new file mode 100644 index 00000000..af2fee35 --- /dev/null +++ b/karbon/core/vobject.cc @@ -0,0 +1,236 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include "vdocument.h" +#include "vfill.h" +#include "vobject.h" +#include "vobject_iface.h" +#include "vstroke.h" + +#include <KoStore.h> +#include <KoGenStyles.h> +#include <KoStyleStack.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <KoOasisLoadingContext.h> +#include <KoOasisStyles.h> + +VObject::VObject( VObject* parent, VState state ) : m_dcop( 0L ) +{ + m_stroke = 0L; + m_fill = 0L; + + m_parent = parent; + m_state = state; + + invalidateBoundingBox(); +} + +VObject::VObject( const VObject& obj ) +{ + m_stroke = 0L; + m_fill = 0L; + + m_parent = obj.m_parent; + m_state = obj.m_state; + + invalidateBoundingBox(); + m_dcop = 0L; + + VDocument *srcDoc = obj.document(); + if( srcDoc && !srcDoc->objectName( &obj ).isEmpty() ) + { + VDocument *dstDoc = document(); + if( dstDoc ) + dstDoc->setObjectName( this, srcDoc->objectName( &obj ) ); + } +} + +VObject::~VObject() +{ + delete( m_stroke ); + delete( m_fill ); + delete m_dcop; +} + +DCOPObject * +VObject::dcopObject() +{ + if ( !m_dcop ) + m_dcop = new VObjectIface( this ); + + return m_dcop; +} + +void +VObject::setStroke( const VStroke& stroke ) +{ + if( !m_stroke ) + m_stroke = new VStroke( this ); + + *m_stroke = stroke; +} + +void +VObject::setFill( const VFill& fill ) +{ + if( !m_fill ) + m_fill = new VFill(); + + *m_fill = fill; +} + +void +VObject::save( QDomElement& element ) const +{ + if( m_stroke ) + m_stroke->save( element ); + + if( m_fill ) + m_fill->save( element ); + + VDocument *doc = document(); + if( doc && !doc->objectName( this ).isEmpty() ) + element.setAttribute( "ID", QString( doc->objectName( this ) ) ); +} + +void +VObject::saveOasis( KoStore *, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + if( !name().isEmpty() ) + docWriter->addAttribute( "draw:name", name() ); + + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -document()->height() ); + + KoGenStyle styleobjectauto( VDocument::STYLE_GRAPHICAUTO, "graphic" ); + saveOasisFill( mainStyles, styleobjectauto ); + if( m_stroke ) + { + // mirror stroke before saving + VStroke stroke( *m_stroke ); + stroke.transform( mat ); + stroke.saveOasis( styleobjectauto ); + } + QString st = mainStyles.lookup( styleobjectauto, "st" ); + if(document()) + docWriter->addAttribute( "draw:id", "obj" + QString::number( index ) ); + docWriter->addAttribute( "draw:style-name", st ); +} + +void +VObject::saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesobjectauto ) const +{ + if( m_fill ) + { + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -document()->height() ); + + // mirror fill before saving + VFill fill( *m_fill ); + fill.transform( mat ); + fill.saveOasis( mainStyles, stylesobjectauto ); + } +} + +void +VObject::load( const QDomElement& element ) +{ + if( !m_stroke ) + m_stroke = new VStroke( this ); + + if( !m_fill ) + m_fill = new VFill(); + + + if( element.tagName() == "STROKE" ) + { + m_stroke->load( element ); + } + else if( element.tagName() == "FILL" ) + { + m_fill->load( element ); + } + + VDocument *doc = document(); + if( doc && !element.attribute( "ID" ).isEmpty() ) + doc->setObjectName( this, element.attribute( "ID" ) ); +} + +bool +VObject::loadOasis( const QDomElement &object, KoOasisLoadingContext &context ) +{ + if( !m_stroke ) + m_stroke = new VStroke( this ); + + if( !m_fill ) + m_fill = new VFill(); + + if( object.hasAttributeNS( KoXmlNS::draw, "style-name" ) ) + context.fillStyleStack( object, KoXmlNS::draw, "style-name", "graphic" ); + + KoStyleStack &styleStack = context.styleStack(); + styleStack.setTypeProperties( "graphic" ); + m_stroke->loadOasis( styleStack ); + m_fill->loadOasis( object, context, this ); + + if( object.hasAttributeNS( KoXmlNS::draw, "name" ) ) + setName( object.attributeNS( KoXmlNS::draw, "name", QString::null ) ); + + return true; +} + +void +VObject::addStyles( const QDomElement* style, KoOasisLoadingContext & context ) +{ + if(style) + { + // this function is necessary as parent styles can have parents themself + if( style->hasAttributeNS( KoXmlNS::style, "parent-style-name" ) ) + addStyles( context.oasisStyles().findStyle( style->attributeNS( KoXmlNS::style, "parent-style-name", QString::null ) ), context ); + context.addStyles( style, "style-name" ); + } +} + +VDocument * +VObject::document() const +{ + VObject *obj = (VObject *)this; + while( obj->parent() ) + obj = obj->parent(); + return dynamic_cast<VDocument *>( obj ); +} + +QString +VObject::name() const +{ + return document() ? document()->objectName( this ) : QString(); +} + +void +VObject::setName( const QString &s ) +{ + if( document() ) + document()->setObjectName( this, s ); +} + diff --git a/karbon/core/vobject.h b/karbon/core/vobject.h new file mode 100644 index 00000000..9aa6885a --- /dev/null +++ b/karbon/core/vobject.h @@ -0,0 +1,299 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VOBJECT_H__ +#define __VOBJECT_H__ + + +#include <KoRect.h> +#include <dcopobject.h> +#include <koffice_export.h> + +class QDomElement; +class VDocument; +class VFill; +class VPainter; +class VStroke; +class VVisitor; +class DCOPObject; +class KoStore; +class KoXmlWriter; +class KoOasisLoadingContext; +class KoGenStyles; +class KoGenStyle; + +/** + * The base class for all karbon objects. Every object should + * have the ability to draw itself using a painter, perform + * hit detection, transform on demand, clone and load/save itself. + * Also each object manages its own bounding box and keeps track of its + * parent object. + */ +class KARBONBASE_EXPORT VObject +{ +public: + enum VState + { + normal = 0, /**< visible, not active */ + normal_locked = 1, /**< visible, but locked (r/o) */ + hidden = 2, /**< hidden */ + hidden_locked = 3, /**< hidden and locked (r/o) */ + deleted = 4, /**< deleted, nearly dead */ + + // shape specific states: + selected = 5, /**< visible, active and can be manipulated by tools */ + edit = 6 /**< visible, active and is currently manipulated by a tool */ + }; + + /** + * Constructs a new object that is child of parent and has the given state. + * + * @param parent the new object's parent + * @param state the new object's state + */ + VObject( VObject* parent, VState state = edit ); + + /** + * Copy constructor. + * Copies parent, state and name of given object. + * + * @param obj the object to copy properties from + */ + VObject( const VObject& obj ); + + /** + * Destroys the object and deletes the stroke, fill and DCOP-object. + */ + virtual ~VObject(); + + /** + * Returns pointer to internal DCOP object. + * + * If no internal DCOP object exist yet, it is created. + */ + virtual DCOPObject* dcopObject(); + + /** + * Draw the object to a painting device. + * + * @param painter abstraction that is used to render to a painting device. + * @param rect represents the visible rectangular area. If this object doesn't + * intersect with this area it is not drawn. + */ + virtual void draw( VPainter* painter, const KoRect* rect = 0L ) const + { + Q_UNUSED( painter ); + Q_UNUSED( rect ); + } + + /** + * Calculates the tightest bounding box around the object. + * + * @return the bounding box. + */ + virtual const KoRect& boundingBox() const + { return m_boundingBox; } + + /** + * Checks if the bounding box is invalid and needs to be recalculated. + * + * @return true if bounding box is invalid. + */ + bool boundingBoxIsInvalid() const + { return m_boundingBoxIsInvalid; } + + /** + * Invalidates the bounding box, so it has to be recalculated. + * This function is public so visitors can access it themself at the right + * time when they manipulate many VSegments. + */ + void invalidateBoundingBox() + { + m_boundingBoxIsInvalid = true; + + if( m_parent ) + m_parent->invalidateBoundingBox(); + } + + /** + * Sets a new parent object. + * + * @param parent the new parent object + */ + void setParent( VObject* parent ) { m_parent = parent; } + + /** + * Returns pointer to current parent object. + * + * @return pointer to current parent object or 0 if no parent object is set + */ + VObject* parent() const { return m_parent; } + + /** + * Get the state the object is in. + * + * @return the object state at time of calling. + */ + VState state() const { return m_state; } + + /** + * Sets the state to a specified new state. + * Note that this will not have any visual effect until draw() is + * called on this object. + * + * @param state the new state. + */ + virtual void setState( const VState state ) { m_state = state; } + + /** + * Gets the object's actual stroke. + * + * @return pointer to the object's stroke + */ + virtual VStroke* stroke() const { return m_stroke; } + + /** + * Gets the object's actual fill. + * + * @return pointer to the object's fill + */ + virtual VFill* fill() const { return m_fill; } + + /** + * Sets the stroke to a given new stroke. + * + * @param stroke the new stroke + */ + virtual void setStroke( const VStroke& stroke ); + + /** + * Sets the fill to a given new fill. + * + * @param fill the new fill + */ + virtual void setFill( const VFill& fill ); + + /** + * Save this object's state to xml. + * + * @param element the DOM element to which the attributes are saved + */ + virtual void save( QDomElement& element ) const; + + /** + * Save this object's state to OpenDocument. + * + * @param store FIXME + * @param docWriter FIXME + * @param mainStyles FIXME + */ + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + + /** + * Load this object's state from xml and initialize + * this object accordingly. + * + * @param element the DOM element from which the attributes are read + */ + virtual void load( const QDomElement& element ); + + /** + * Load this object's state from OpenDocument and initialize + * this object accordingly. + * + * @param element the DOM element to read attributes from + * @param context FIXME + */ + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + /** + * Create an exact copy of this object. + * + * @return the exact object copy + */ + virtual VObject* clone() const = 0; + + /** + * Accept a VVisitor. + */ + virtual void accept( VVisitor& /*visitor*/ ) + { } + + /** + * This function is important for undo/redo. It inserts newObject in front + * of oldObject. + * + * @param newObject the new object to insert + * @param oldObject the old object the new object is inserted in front of + */ + virtual void insertInfrontOf( VObject* newObject, VObject* oldObject ) + { + Q_UNUSED( newObject ); + Q_UNUSED( oldObject ); + } + + /** + * Returns the name of the object. + * + * @return the object's name + */ + virtual QString name() const; + + /** + * Sets the object's name to a given new name. + * + * @param s the new object name + */ + void setName( const QString &s ); + + /** + * Return document the object belongs to. + * + * @return pointer to parent document or 0 if object does not belong to a document + */ + VDocument *document() const; + +protected: + /** + * Adds a new given style to the specified OASIS context + * + * @param style FIXME + * @param context FIXME + */ + void addStyles( const QDomElement* style, KoOasisLoadingContext & context ); + + virtual void saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesojectauto ) const; + +protected: + mutable KoRect m_boundingBox; /**< the object's bounding box */ + mutable VState m_state : 8; /**< the object's state */ + mutable bool m_boundingBoxIsInvalid : 1; /**< the flag stating if the bounding box is valid */ + + VStroke* m_stroke; /**< the object's stroke */ + VFill* m_fill; /**< the object's fill */ + + DCOPObject *m_dcop; /**< the object's DCOP object */ + +private: + VObject* m_parent; +}; + +#endif + diff --git a/karbon/core/vobject_iface.cc b/karbon/core/vobject_iface.cc new file mode 100644 index 00000000..c93b68d6 --- /dev/null +++ b/karbon/core/vobject_iface.cc @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vobject_iface.h" +#include "vobject.h" + +#include <kapplication.h> +#include <dcopclient.h> + +VObjectIface::VObjectIface( VObject* obj ) + : DCOPObject(), m_object( obj ) +{ +} + +int +VObjectIface::state() const +{ + return (int)m_object->state(); +} + +void +VObjectIface::setState( int state ) +{ + return m_object->setState( (VObject::VState)state ); +} + +DCOPRef +VObjectIface::parent() const +{ + if( !m_object->parent() ) + return DCOPRef(); + + return DCOPRef( kapp->dcopClient()->appId(), m_object->parent()->dcopObject()->objId() ); +} + diff --git a/karbon/core/vobject_iface.h b/karbon/core/vobject_iface.h new file mode 100644 index 00000000..e1684ba2 --- /dev/null +++ b/karbon/core/vobject_iface.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VOBJECT_IFACE_H__ +#define __VOBJECT_IFACE_H__ + +#include <KoRect.h> + +class VObject; +class QDomElement; +class VFill; +class VPainter; +class VStroke; +class VVisitor; + +#include <dcopobject.h> +#include <dcopref.h> + +class VObjectIface : public DCOPObject +{ + K_DCOP + +public: + VObjectIface( VObject *obj ); + +k_dcop: + /*void draw( VPainter*, const KoRect* = 0L ) const {} + const KoRect& boundingBox() const { return m_boundingBox; } + + bool boundingBoxIsInvalid() const; + void invalidateBoundingBox(); + void setParent( VObject* parent ) { m_parent = parent; }*/ + + DCOPRef parent() const; + + int state() const; + void setState( int state ); + + /*VStroke* stroke() const { return m_stroke; } + VFill* fill() const { return m_fill; } + void setStroke( const VStroke& stroke ); + void setFill( const VFill& fill ); + void save( QDomElement& element ) const; + void load( const QDomElement& element ); + VObject* clone() const = 0; + void accept( VVisitor& ) {} + void insertInfrontOf( VObject* , VObject* ) { }*/ + +private: + VObject* m_object; +}; + +#endif + diff --git a/karbon/core/vpath.cc b/karbon/core/vpath.cc new file mode 100644 index 00000000..a9fcc8a1 --- /dev/null +++ b/karbon/core/vpath.cc @@ -0,0 +1,1153 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <math.h> + +#include <qdom.h> +#include <qvaluelist.h> +#include <qwmatrix.h> + +#include "vpath.h" +#include "vsegment.h" +#include "vvisitor.h" + +#include <kdebug.h> + + +class VSubpathIteratorList +{ +public: + VSubpathIteratorList() + : m_list( 0L ), m_iterator( 0L ) + {} + + ~VSubpathIteratorList() + { + notifyClear( true ); + delete m_list; + } + + void add( VSubpathIterator* itr ) + { + if( !m_iterator ) + m_iterator = itr; + else if( m_list ) + m_list->push_front( itr ); + else + { + m_list = new QValueList<VSubpathIterator*>; + m_list->push_front( itr ); + } + } + + void remove( VSubpathIterator* itr ) + { + if( m_iterator == itr ) + m_iterator = 0L; + else if( m_list ) + { + m_list->remove( itr ); + + if( m_list->isEmpty() ) + { + delete m_list; + m_list = 0L; + } + } + } + + void notifyClear( bool zeroList ) + { + if( m_iterator ) + { + if( zeroList ) + m_iterator->m_list = 0L; + + m_iterator->m_current = 0L; + } + + if( m_list ) + { + for( + QValueList<VSubpathIterator*>::Iterator itr = m_list->begin(); + itr != m_list->end(); + ++itr ) + { + if( zeroList ) + ( *itr )->m_list = 0L; + + ( *itr )->m_current = 0L; + } + } + } + + void notifyRemove( VSegment* segment, VSegment* current ) + { + if( m_iterator ) + { + if( m_iterator->m_current == segment ) + m_iterator->m_current = current; + } + + if( m_list ) + { + for( + QValueList<VSubpathIterator*>::Iterator itr = m_list->begin(); + itr != m_list->end(); + ++itr ) + { + if( ( *itr )->m_current == segment ) + ( *itr )->m_current = current; + } + } + } + +private: + QValueList<VSubpathIterator*>* m_list; + VSubpathIterator* m_iterator; +}; + + +VSubpath::VSubpath( VObject* parent ) + : VObject( parent ) +{ + m_isClosed = false; + + m_first = m_last = m_current = 0L; + m_number = 0; + m_currentIndex = -1; + m_iteratorList = 0L; + + // Add an initial segment. + append( new VSegment( 1 ) ); +} + +VSubpath::VSubpath( const VSubpath& list ) + : VObject( list ) +{ + m_isClosed = list.isClosed(); + + m_first = m_last = m_current = 0L; + m_number = 0; + m_currentIndex = -1; + m_iteratorList = 0L; + + VSegment* segment = list.m_first; + + while( segment ) + { + append( segment->clone() ); + segment = segment->m_next; + } +} + +VSubpath::VSubpath( const VSegment& segment ) + : VObject( 0L ) +{ + m_isClosed = false; + + m_first = m_last = m_current = 0L; + m_number = 0; + m_currentIndex = -1; + m_iteratorList = 0L; + + // The segment is not a "begin" segment. + if( segment.prev() ) + { + // Add an initial segment. + append( new VSegment( 1 ) ); + + // Move the "begin" segment to the new segment's previous knot. + moveTo( segment.prev()->knot() ); + } + + // Append a copy of the segment. + append( segment.clone() ); +} + +VSubpath::~VSubpath() +{ + clear(); + delete m_iteratorList; +} + +const KoPoint& +VSubpath::currentPoint() const +{ + return getLast()->knot(); +} + +bool +VSubpath::moveTo( const KoPoint& p ) +{ + // Move "begin" segment if path is still empty. + if( isEmpty() ) + { + getLast()->setKnot( p ); + return true; + } + + return false; +} + +bool +VSubpath::lineTo( const KoPoint& p ) +{ + if( isClosed() ) + return false; + + VSegment* s = new VSegment( 1 ); + + s->setDegree( 1 ); + s->setKnot( p ); + + append( s ); + + return true; +} + +bool +VSubpath::curveTo( + const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 ) +{ + if( isClosed() ) + return false; + + VSegment* s = new VSegment(); + + s->setDegree( 3 ); + s->setPoint( 0, p1 ); + s->setPoint( 1, p2 ); + s->setPoint( 2, p3 ); + + append( s ); + + + return true; +} + +bool +VSubpath::curve1To( const KoPoint& p2, const KoPoint& p3 ) +{ + if( isClosed() ) + return false; + + VSegment* s = new VSegment(); + + s->setDegree( 3 ); + s->setPoint( 0, currentPoint() ); + s->setPoint( 1, p2 ); + s->setPoint( 2, p3 ); + + append( s ); + + + return true; +} + +bool +VSubpath::curve2To( const KoPoint& p1, const KoPoint& p3 ) +{ + if( isClosed() ) + return false; + + VSegment* s = new VSegment(); + + s->setDegree( 3 ); + s->setPoint( 0, p1 ); + s->setPoint( 1, p3 ); + s->setPoint( 2, p3 ); + + append( s ); + + + return true; +} + +bool +VSubpath::arcTo( + const KoPoint& p1, const KoPoint& p2, const double r ) +{ + /* This routine is inspired by code in GNU ghostscript. + * + * |- P1B3 -| + * + * |- - - T12- - -| + * + * - - P1 x....__--o.....x P2 + * | | : _/ B3 + * P1B0 : / + * | :/ + * | | + * - T10 o B0 + * | + * | | + * | + * | | + * - x P0 + */ + + if( isClosed() || r < 0.0 ) + return false; + + + // We need to calculate the tangent points. Therefore calculate tangents + // T10=P1P0 and T12=P1P2 first. + double dx0 = currentPoint().x() - p1.x(); + double dy0 = currentPoint().y() - p1.y(); + double dx2 = p2.x() - p1.x(); + double dy2 = p2.y() - p1.y(); + + // Calculate distance squares. + double dsqT10 = dx0 * dx0 + dy0 * dy0; + double dsqT12 = dx2 * dx2 + dy2 * dy2; + + // We now calculate tan(a/2) where a is the angle between T10 and T12. + // We benefit from the facts T10*T12 = |T10|*|T12|*cos(a), + // |T10xT12| = |T10|*|T12|*sin(a) (cross product) and tan(a/2) = sin(a)/[1-cos(a)]. + double num = dy0 * dx2 - dy2 * dx0; + + double denom = sqrt( dsqT10 * dsqT12 ) - ( dx0 * dx2 + dy0 * dy2 ); + + // The points are colinear. + if( 1.0 + denom == 1.0 ) + { + // Just add a line. + lineTo( p1 ); + } + else + { + // |P1B0| = |P1B3| = r * tan(a/2). + double dP1B0 = fabs( r * num / denom ); + + // B0 = P1 + |P1B0| * T10/|T10|. + KoPoint b0 = p1 + KoPoint( dx0, dy0 ) * ( dP1B0 / sqrt( dsqT10 ) ); + + // If B0 deviates from current point P0, add a line to it. + if( !b0.isNear( currentPoint(), VGlobal::isNearRange ) ) + lineTo( b0 ); + + // B3 = P1 + |P1B3| * T12/|T12|. + KoPoint b3 = p1 + KoPoint( dx2, dy2 ) * ( dP1B0 / sqrt( dsqT12 ) ); + + + // The two bezier-control points are located on the tangents at a fraction + // of the distance[ tangent points <-> tangent intersection ]. + const KoPoint d = p1 - b0; + + double distsq = d * d; + + double rsq = r * r; + + double fract; + + // r is very small. + if( distsq >= rsq * VGlobal::veryBigNumber ) + { + // Assume dist = r = 0. + fract = 0.0; + } + else + { + fract = ( 4.0 / 3.0 ) / ( 1.0 + sqrt( 1.0 + distsq / rsq ) ); + } + + KoPoint b1 = b0 + ( p1 - b0 ) * fract; + KoPoint b2 = b3 + ( p1 - b3 ) * fract; + + // Finally add the bezier-segment. + curveTo( b1, b2, b3 ); + } + + return true; +} + +void +VSubpath::close() +{ + // In the case the list is 100% empty (which should actually never happen), + // append a "begin" first, to avoid a crash. + if( count() == 0 ) + append( new VSegment( 1 ) ); + + // Move last segment if we are already closed. + if( isClosed() ) + { + getLast()->setKnot( getFirst()->knot() ); + } + // Append a line, if necessary. + else + { + if( + getLast()->knot().isNear( + getFirst()->knot(), VGlobal::isNearRange ) ) + { + // Move last knot. + getLast()->setKnot( getFirst()->knot() ); + } + else + { + // Add a line. + lineTo( getFirst()->knot() ); + } + + m_isClosed = true; + } +} + +bool +VSubpath::pointIsInside( const KoPoint& p ) const +{ + // If the point is not inside the boundingbox, it cannot be inside the path either. + if( !boundingBox().contains( p ) ) + return false; + + // First check if the point is inside the knot polygon (beziers are treated + // as lines). + + /* This algorithm is taken from "Fast Winding Number Inclusion of a Point + * in a Polygon" by Dan Sunday, geometryalgorithms.com. + */ + + /* + int windingNumber = 0; + + // Ommit first segment. + VSegment* segment = getFirst()->next(); + + while( segment ) + { + if( segment->prev()->knot().y() <= p.y() ) + { + // Upward crossing. + if( segment->knot().y() > p.y() ) + { + // Point is left. + if( segment->pointIsLeft( p ) > 0 ) + { + // Valid up intersection. + ++windingNumber; + } + } + } + else + { + // Downward crossing. + if( segment->knot().y() <= p.y() ) + { + // Point is right. + if( segment->pointIsLeft( p ) < 0 ) + { + // Valid down intersection. + --windingNumber; + } + } + } + + segment = segment->next(); + } + + if( static_cast<bool>( windingNumber ) ) + return true; + */ + + // Then check if the point is located in between the knot polygon + // and the bezier curves. + + /* We rotate each segment in order to make their chord (the line between + * the previous knot and the knot ) parallel to the x-axis. Then we + * calculate y(xp) on the segment for the rotated input point (xp,yp) + * and compare y(xp) with yp. + */ +// TODO + + // cache the closed evaluation + bool closed = isClosed() || getLast()->knot() == getFirst()->knot(); + + QValueList<double> rparams; + + VSegment* segment = getFirst()->next(); + + // move all segements so that p is the origin + // and compute their intersections with the x-axis + while( segment ) + { + VSubpath tmpCurve( 0L ); + tmpCurve.append( new VSegment( segment->degree() ) ); + + for( int i = 0; i <= segment->degree(); ++i ) + tmpCurve.current()->setP(i, segment->p(i)-p ); + + tmpCurve.current()->rootParams( rparams ); + + segment = segment->next(); + } + + // if the path is not closed, compute the intersection of + // the line through the first and last knot and the x-axis too + if( ! closed ) + { + KoPoint prevKnot = getLast()->knot() - p; + KoPoint nextKnot = getFirst()->knot() - p; + + double dx = nextKnot.x() - prevKnot.x(); + double dy = nextKnot.y() - prevKnot.y(); + if( dx == 0.0 ) + { + rparams.append( nextKnot.x() ); + } + else if( dy != 0.0 ) + { + if( ( prevKnot.y() < 0.0 && nextKnot.y() > 0.0 ) || ( prevKnot.y() > 0.0 && nextKnot.y() < 0.0 ) ) + { + double n = prevKnot.y() - dy / dx * prevKnot.x(); + rparams.append( -n * dx / dy ); + } + } + } + + kdDebug(38000) << "intersection count: " << rparams.count() << endl; + + // sort all intersections + qHeapSort( rparams ); + + QValueList<double>::iterator itr, etr = rparams.end(); + + for( itr = rparams.begin(); itr != etr; ++itr ) + kdDebug(38000) << "intersection: " << *itr << endl; + + if( closed ) + { + // pair the intersections and check if the origin is within a pair + for( itr = rparams.begin(); itr != etr; ++itr ) + { + if( *itr > 0.0 ) + return false; + + if( ++itr == etr ) + return false; + + if( *itr > 0.0 ) + return true; + } + } + else + { + // only check if point is between first and last intersection if we have an open path + if ( rparams.front() < 0.0 && rparams.back() > 0.0 ) + return true; + } + + return false; +} + +bool +VSubpath::intersects( const VSegment& s ) const +{ + // Check if path is empty and if boundingboxes intersect. + if( + isEmpty() || + !boundingBox().intersects( s.boundingBox() ) ) + { + return false; + } + + + // Ommit first segment. + VSegment* segment = getFirst()->next(); + + while( segment ) + { + if( segment->intersects( s ) ) + { + return true; + } + + segment = segment->next(); + } + + return false; +} + +bool +VSubpath::counterClockwise() const +{ + /* This algorithm is taken from the FAQ of comp.graphics.algorithms: + * "Find the lowest vertex (or, if there is more than one vertex with the + * same lowest coordinate, the rightmost of those vertices) and then take + * the cross product of the edges fore and aft of it." + */ + + // A non closed path does not have a winding. + if( !isClosed() ) + { + return false; + } + + + VSegment* segment = getFirst(); + + // We save the segment not the knot itself. Initialize it with the + // first segment: + const VSegment* bottomRight = getFirst(); + + while( segment ) + { + if( segment->knot().y() < bottomRight->knot().y() ) + bottomRight = segment; + else if( segment->knot().y() - bottomRight->knot().y() + < VGlobal::isNearRange ) + { + if( segment->knot().x() > bottomRight->knot().x() ) + bottomRight = segment; + } + + segment = segment->next(); + } + + + // Catch boundary case (bottomRight is first or last segment): + const VSegment* current; + const VSegment* next; + + if( bottomRight == getFirst() ) + current = getLast(); + else + current = bottomRight; + + if( bottomRight == getLast() ) + next = getFirst()->next(); + else + next = bottomRight->next(); + + // Check "z-component" of cross product: + return + ( next->knot().x() - next->prev()->knot().x() ) * + ( current->knot().y() - current->prev()->knot().y() ) + - + ( next->knot().y() - next->prev()->knot().y() ) * + ( current->knot().x() - current->prev()->knot().x() ) < 0.0; +} + +void +VSubpath::revert() +{ + // Catch case where the list is "empty". + if( isEmpty() ) + return; + + + VSubpath list( parent() ); + list.moveTo( getLast()->knot() ); + + VSegment* segment = getLast(); + + while( segment->prev() ) + { + list.append( segment->revert() ); + segment = segment->prev(); + } + + list.m_isClosed = isClosed(); + + *this = list; +} + +const KoRect& +VSubpath::boundingBox() const +{ + if( m_boundingBoxIsInvalid ) + { + // Reset the boundingbox. + m_boundingBox = KoRect(); + + VSegment* segment = m_first; + + while( segment ) + { + if( segment->state() != VSegment::deleted ) + m_boundingBox |= segment->boundingBox(); + + segment = segment->m_next; + } + + m_boundingBoxIsInvalid = false; + } + + return m_boundingBox; +} + +VSubpath* +VSubpath::clone() const +{ + return new VSubpath( *this ); +} + +void +VSubpath::saveSvgPath( QString &d ) const +{ + // Save segments. + VSegment* segment = getFirst(); + + while( segment ) + { + if( segment->state() == VSegment::normal ) + { + if( segment->degree() <= 2 ) + { + // Line. + if( segment->prev() ) + { + d += QString( "L%1 %2" ). + arg( segment->knot().x() ).arg( segment->knot().y() ); + } + // Moveto. + else + { + d += QString( "M%1 %2" ). + arg( segment->knot().x() ).arg( segment->knot().y() ); + } + } + // Bezier ( degree >= 3 ). + else + { + // We currently treat all beziers as cubic beziers. + d += QString( "C%1 %2 %3 %4 %5 %6" ). + arg( segment->point( segment->degree() - 3 ).x() ). + arg( segment->point( segment->degree() - 3 ).y() ). + arg( segment->point( segment->degree() - 2 ).x() ). + arg( segment->point( segment->degree() - 2 ).y() ). + arg( segment->knot().x() ). + arg( segment->knot().y() ); + } + } + + segment = segment->m_next; + } + + if( isClosed() ) + d += "Z"; +} + +// TODO: remove this backward compatibility function after koffice 1.3.x +void +VSubpath::load( const QDomElement& element ) +{ + // We might have a "begin" segment. + clear(); + + QDomNodeList list = element.childNodes(); + + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement segment = list.item( i ).toElement(); + + VSegment* s = new VSegment(); + s->load( segment ); + append( s ); + } + } + + if( element.attribute( "isClosed" ) == 0 ? false : true ) + close(); +} + +void +VSubpath::accept( VVisitor& visitor ) +{ + visitor.visitVSubpath( *this ); +} + + +VSubpath& +VSubpath::operator=( const VSubpath& list ) +{ + if( this == &list ) + return *this; + + m_isClosed = list.isClosed(); + + clear(); + + VSegment* segment = list.m_first; + + while( segment ) + { + append( segment->clone() ); + segment = segment->m_next; + } + + m_current = m_first; + m_currentIndex = 0; + + return *this; +} + +bool +VSubpath::insert( const VSegment* segment ) +{ + if( m_currentIndex == -1 ) + return false; + + VSegment* s = const_cast<VSegment*>( segment ); + + VSegment* prev = m_current->m_prev; + + m_current->m_prev = s; + prev->m_next = s; + s->m_prev = prev; + s->m_next = m_current; + + m_current = s; + ++m_number; + + invalidateBoundingBox(); + + return true; +} + +bool +VSubpath::insert( uint index, const VSegment* segment ) +{ + VSegment* s = const_cast<VSegment*>( segment ); + + if( index == 0 ) + { + prepend( s ); + return true; + } + else if( index == m_number ) + { + append( s ); + return true; + } + + VSegment* next = locate( index ); + + if( !next ) + return false; + + VSegment* prev = next->m_prev; + + next->m_prev = s; + prev->m_next = s; + s->m_prev = prev; + s->m_next = next; + + m_current = s; + ++m_number; + + invalidateBoundingBox(); + + return true; +} + +void +VSubpath::prepend( const VSegment* segment ) +{ + VSegment* s = const_cast<VSegment*>( segment ); + + s->m_prev = 0L; + + if( ( s->m_next = m_first ) ) + m_first->m_prev = s; + else + m_last = s; + + m_first = m_current = s; + + ++m_number; + m_currentIndex = 0; + + invalidateBoundingBox(); +} + +void +VSubpath::append( const VSegment* segment ) +{ + VSegment* s = const_cast<VSegment*>( segment ); + + s->m_next = 0L; + + if( ( s->m_prev = m_last ) ) + m_last->m_next = s; + else + m_first = s; + + m_last = m_current = s; + + m_currentIndex = m_number; + ++m_number; + + invalidateBoundingBox(); +} + +void +VSubpath::clear() +{ + VSegment* segment = m_first; + + m_first = m_last = m_current = 0L; + m_number = 0; + m_currentIndex = -1; + + if( m_iteratorList ) + m_iteratorList->notifyClear( false ); + + VSegment* prev; + + while( segment ) + { + prev = segment; + segment = segment->m_next; + delete prev; + } + + m_isClosed = false; + + invalidateBoundingBox(); +} + +VSegment* +VSubpath::first() +{ + if( m_first ) + { + m_currentIndex = 0; + return m_current = m_first; + } + + return 0L; +} + +VSegment* +VSubpath::last() +{ + if( m_last ) + { + m_currentIndex = m_number - 1; + return m_current = m_last; + } + + return 0L; +} + +VSegment* +VSubpath::prev() +{ + if( m_current ) + { + if( m_current->m_prev ) + { + --m_currentIndex; + return m_current = m_current->m_prev; + } + + m_currentIndex = -1; + m_current = 0L; + } + + return 0L; +} + +VSegment* +VSubpath::next() +{ + if( m_current ) + { + if( m_current->m_next ) + { + ++m_currentIndex; + return m_current = m_current->m_next; + } + + m_currentIndex = -1; + m_current = 0L; + } + + return 0L; +} + +VSegment* +VSubpath::locate( uint index ) +{ + if( index == static_cast<uint>( m_currentIndex ) ) + return m_current; + + if( !m_current && m_first ) + { + m_current = m_first; + m_currentIndex = 0; + } + + VSegment* segment; + int distance = index - m_currentIndex; + bool forward; + + if( index >= m_number ) + return 0L; + + if( distance < 0 ) + distance = -distance; + + if( + static_cast<uint>( distance ) < index && + static_cast<uint>( distance ) < m_number - index ) + { + segment = m_current; + forward = index > static_cast<uint>( m_currentIndex ); + } + else if( index < m_number - index ) + { + segment = m_first; + distance = index; + forward = true; + } + else + { + segment = m_last; + distance = m_number - index - 1; + if( distance < 0 ) + distance = 0; + forward = false; + } + + if( forward ) + { + while( distance-- ) + segment = segment->m_next; + } + else + { + while( distance-- ) + segment = segment->m_prev; + } + + m_currentIndex = index; + return m_current = segment; +} + + +VSubpathIterator::VSubpathIterator( const VSubpath& list ) +{ + m_list = const_cast<VSubpath*>( &list ); + m_current = m_list->m_first; + + if( !m_list->m_iteratorList ) + m_list->m_iteratorList = new VSubpathIteratorList(); + + m_list->m_iteratorList->add( this ); +} + +VSubpathIterator::VSubpathIterator( const VSubpathIterator& itr ) +{ + m_list = itr.m_list; + m_current = itr.m_current; + + if( m_list ) + m_list->m_iteratorList->add( this ); +} + +VSubpathIterator::~VSubpathIterator() +{ + if( m_list ) + m_list->m_iteratorList->remove( this ); +} + +VSubpathIterator& +VSubpathIterator::operator=( const VSubpathIterator& itr ) +{ + if( m_list ) + m_list->m_iteratorList->remove( this ); + + m_list = itr.m_list; + m_current = itr.m_current; + + if( m_list ) + m_list->m_iteratorList->add( this ); + + return *this; +} + +VSegment* +VSubpathIterator::current() const +{ + // If m_current points to a deleted segment, find the next not + // deleted segment. + if( + m_current && + m_current->state() == VSegment::deleted ) + { + return m_current->next(); + } + + return m_current; +} + +VSegment* +VSubpathIterator::operator()() +{ + if( VSegment* const old = current() ) + { + m_current = current()->next(); + return old; + } + + return 0L; +} + +VSegment* +VSubpathIterator::operator++() +{ + if( current() ) + return m_current = current()->next(); + + return 0L; +} + +VSegment* +VSubpathIterator::operator+=( uint i ) +{ + while( current() && i-- ) + m_current = current()->next(); + + return current(); +} + +VSegment* +VSubpathIterator::operator--() +{ + if( current() ) + return m_current = current()->prev(); + + return 0L; +} + +VSegment* +VSubpathIterator::operator-=( uint i ) +{ + while( current() && i-- ) + m_current = current()->prev(); + + return current(); +} + diff --git a/karbon/core/vpath.h b/karbon/core/vpath.h new file mode 100644 index 00000000..3287a75e --- /dev/null +++ b/karbon/core/vpath.h @@ -0,0 +1,203 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPATH_H__ +#define __VPATH_H__ + + +#include <KoPoint.h> + +#include "vobject.h" +#include <koffice_export.h> + +class QDomElement; +class QWMatrix; +class VSubpathIteratorList; +class VSegment; +class VVisitor; + + +/** + * VSubpath provides a sophisticated list of VSegment. Noted: it also may contain + * segments which are marked "deleted". If you are not interested in those undo/redo + * housholding data, please always use a VSubpathIterator to access segments. + */ + +class KARBONBASE_EXPORT VSubpath : public VObject +{ + friend class VSubpathIterator; + +public: + VSubpath( VObject* parent ); + VSubpath( const VSubpath& list ); + VSubpath( const VSegment& segment ); + virtual ~VSubpath(); + + const KoPoint& currentPoint() const; + + bool moveTo( const KoPoint& p ); + bool lineTo( const KoPoint& p ); + bool curveTo( + const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 ); + bool curve1To( + const KoPoint& p2, const KoPoint& p3 ); + bool curve2To( + const KoPoint& p1, const KoPoint& p3 ); + bool arcTo( + const KoPoint& p1, const KoPoint& p2, const double r ); + + bool isClosed() const + { + return m_isClosed; + } + + void close(); + + + /** + * Returns true if point p is located inside the path. + * The winding number test is used. + */ + bool pointIsInside( const KoPoint& p ) const; + + /** + * Returns true if the segment intersects this path. + */ + bool intersects( const VSegment& segment ) const; + + + /** + * Returns false if segmentlist is oriented clockwise. + */ + bool counterClockwise() const; + + /** + * Reverts the winding orientation. + */ + void revert(); + + + /** + * Returns true if the current path is "emtpy". That means that it has + * zero or just one ( == "begin") segment. + */ + bool isEmpty() const + { + return count() <= 1; + } + + + virtual const KoRect& boundingBox() const; + + + virtual void save( QDomElement& /*element*/) const + { } // VSubpaths cant be saved. + + // TODO: remove this backward compatibility function after koffice 1.3.x + virtual void load( const QDomElement& element ); + + void saveSvgPath( QString & ) const; + + + virtual VSubpath* clone() const; + + virtual void accept( VVisitor& visitor ); + + + // General list stuff. + VSubpath& operator=( const VSubpath& list ); + + bool insert( const VSegment* segment ); + bool insert( uint i, const VSegment* segment ); + void prepend( const VSegment* segment ); + void append( const VSegment* segment ); + void clear(); + + uint count() const + { + return m_number; + } + + VSegment* current() const + { + return m_current; + } + + VSegment* getFirst() const + { + return m_first; + } + + VSegment* getLast() const + { + return m_last; + } + + VSegment* first(); + VSegment* last(); + VSegment* prev(); + VSegment* next(); + +private: + VSegment* locate( uint index ); + + VSegment* m_first; + VSegment* m_last; + VSegment* m_current; + + int m_currentIndex; + uint m_number : 31; + + bool m_isClosed : 1; + + VSubpathIteratorList* m_iteratorList; +}; + + +/** + * VSubpathIterator provides an iterator class for highlevel path access. + * Use VSubpathIterator whenever you want to access segments but are not interested + * in undo/redo operations with (deleted) segments. + */ + +class KARBONBASE_EXPORT VSubpathIterator +{ + friend class VSubpathIteratorList; + +public: + VSubpathIterator( const VSubpath& list ); + VSubpathIterator( const VSubpathIterator& itr ); + ~VSubpathIterator(); + + VSubpathIterator& operator=( const VSubpathIterator& itr ); + + VSegment* current() const; + VSegment* operator()(); + VSegment* operator++(); + VSegment* operator+=( uint i ); + VSegment* operator--(); + VSegment* operator-=( uint i ); + +private: + VSubpath* m_list; + VSegment* m_current; +}; + +#endif + diff --git a/karbon/core/vpattern.cc b/karbon/core/vpattern.cc new file mode 100644 index 00000000..9929a1b9 --- /dev/null +++ b/karbon/core/vpattern.cc @@ -0,0 +1,140 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include "vpattern.h" +#include <qpixmap.h> +#define THUMB_SIZE 30 + +VPattern::VPattern() +{ + m_valid = false; + validThumb = false; +} + +VPattern::VPattern( const QString &tilename ) +{ + load( tilename ); +} + +void +VPattern::load( const QString &tilename ) +{ + m_tilename = tilename; + bool ok = m_image.load( tilename ); + + if( !ok ) + { + m_valid = false; + return; + } + + m_image = m_image.convertDepth( 32 ); + m_pixmap.convertFromImage(m_image, QPixmap::AutoColor); + if( m_image.width() > THUMB_SIZE || m_image.height() > THUMB_SIZE ) + { + int xsize = THUMB_SIZE; + int ysize = THUMB_SIZE; + int picW = m_image.width(); + int picH = m_image.height(); + if( picW > picH ) + { + float yFactor = (float)((float)(float)picH/(float)picW); + ysize = (int)(yFactor * (float)THUMB_SIZE); + if(ysize > 30) ysize = 30; + } + else if( picW < picH ) + { + float xFactor = (float)((float)picW/(float)picH); + xsize = (int)(xFactor * (float)THUMB_SIZE); + if(xsize > 30) xsize = 30; + } + + QImage thumbImg = m_image.smoothScale( xsize, ysize ); + m_pixmapThumb.convertFromImage( thumbImg ); + validThumb = true; + } + m_valid = !m_image.isNull(); +} + +unsigned char * +VPattern::pixels() +{ + return m_image.bits(); +} + +unsigned int +VPattern::tileWidth() const +{ + return m_image.width(); +} + +unsigned int +VPattern::tileHeight() const +{ + return m_image.height(); +} + +void +VPattern::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "PATTERN" ); + + me.setAttribute( "originX", m_origin.x() ); + me.setAttribute( "originY", m_origin.y() ); + me.setAttribute( "vectorX", m_vector.x() ); + me.setAttribute( "vectorY", m_vector.y() ); + + me.setAttribute( "tilename", m_tilename ); + + element.appendChild( me ); +} + +void +VPattern::load( const QDomElement& element ) +{ + m_origin.setX( element.attribute( "originX", "0.0" ).toDouble() ); + m_origin.setY( element.attribute( "originY", "0.0" ).toDouble() ); + m_vector.setX( element.attribute( "vectorX", "0.0" ).toDouble() ); + m_vector.setY( element.attribute( "vectorY", "0.0" ).toDouble() ); + + m_tilename = element.attribute( "tilename" ); + load( m_tilename ); +} + +void +VPattern::transform( const QWMatrix &m ) +{ + m_origin = m_origin.transform( m ); + m_vector = m_vector.transform( m ); +} + +QPixmap& VPattern::pixmap() const +{ + return (QPixmap&)m_pixmap; +} + +QPixmap& VPattern::thumbPixmap() const +{ + return (QPixmap&)m_pixmapThumb; +} + + + diff --git a/karbon/core/vpattern.h b/karbon/core/vpattern.h new file mode 100644 index 00000000..04870d7d --- /dev/null +++ b/karbon/core/vpattern.h @@ -0,0 +1,73 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPATTERN_H__ +#define __VPATTERN_H__ + +#include <KoPoint.h> +#include <koIconChooser.h> +#include <qimage.h> +#include <qpixmap.h> +#include <koffice_export.h> +class QDomElement; + + +class KARBONBASE_EXPORT VPattern : public KoIconItem +{ +public: + VPattern(); + VPattern( const QString &tilename ); + + unsigned char *pixels(); + unsigned int tileWidth() const; + unsigned int tileHeight() const; + + KoPoint origin() const { return m_origin; } + void setOrigin( const KoPoint &origin ) { m_origin = origin; } + + KoPoint vector() const { return m_vector; } + void setVector( const KoPoint &vector ) { m_vector = vector; } + + void load( const QString &tilename ); + + void save( QDomElement& element ) const; + void load( const QDomElement& element ); + + void transform( const QWMatrix& m ); + + // for KoIconItem + QPixmap& pixmap() const ; + QPixmap& thumbPixmap() const; + + bool isValid() const { return m_valid; } + + QString tilename() const { return m_tilename; } + +private: + // coordinates: + KoPoint m_origin; + KoPoint m_vector; + QImage m_image; + QPixmap m_pixmap; + QPixmap m_pixmapThumb; + QString m_tilename; + bool m_valid; +}; + +#endif diff --git a/karbon/core/vsegment.cc b/karbon/core/vsegment.cc new file mode 100644 index 00000000..3f0a4590 --- /dev/null +++ b/karbon/core/vsegment.cc @@ -0,0 +1,1112 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <qdom.h> + +#include "vpainter.h" +#include "vpath.h" +#include "vsegment.h" + +#include <kdebug.h> + +VSegment::VSegment( unsigned short deg ) +{ + m_degree = deg; + + m_nodes = new VNodeData[ degree() ]; + + for( unsigned short i = 0; i < degree(); ++i ) + selectPoint( i ); + + m_state = normal; + + m_prev = 0L; + m_next = 0L; +} + +VSegment::VSegment( const VSegment& segment ) +{ + m_degree = segment.degree(); + + m_nodes = new VNodeData[ degree() ]; + + m_state = segment.m_state; + + // Copying the pointers m_prev/m_next has some advantages (see VSegment::length()). + // Inserting a segment into a path overwrites these anyway. + m_prev = segment.m_prev; + m_next = segment.m_next; + + // Copy points. + for( unsigned short i = 0; i < degree(); i++ ) + { + setPoint( i, segment.point( i ) ); + selectPoint( i, segment.pointIsSelected( i ) ); + } +} + +VSegment::~VSegment() +{ + delete[]( m_nodes ); +} + +void +VSegment::setDegree( unsigned short deg ) +{ + // Do nothing if old and new degrees are identical. + if( degree() == deg ) + return; + + // TODO : this code is fishy, please make it sane + + // Remember old nodes. + VNodeData* oldNodes = m_nodes; + KoPoint oldKnot = knot(); + + // Allocate new node data. + m_nodes = new VNodeData[ deg ]; + + if( deg == 1 ) + m_nodes[ 0 ].m_vector = oldKnot; + else + { + // Copy old node data (from the knot "backwards". + unsigned short offset = kMax( 0, deg - m_degree ); + + for( unsigned short i = offset; i < deg; ++i ) + { + m_nodes[ i ].m_vector = oldNodes[ i - offset ].m_vector; + } + + // Fill with "zeros" if necessary. + for( unsigned short i = 0; i < offset; ++i ) + { + m_nodes[ i ].m_vector = KoPoint( 0.0, 0.0 ); + } + } + + // Set new degree. + m_degree = deg; + + // Delete old nodes. + delete[]( oldNodes ); +} + +void +VSegment::draw( VPainter* painter ) const +{ + // Don't draw a deleted segment. + if( state() == deleted ) + return; + + + if( prev() ) + { + if( degree() == 3 ) + { + painter->curveTo( point( 0 ), point( 1 ), point( 2 ) ); + } + else + { + painter->lineTo( knot() ); + } + } + else + { + painter->moveTo( knot() ); + } +} + +bool +VSegment::isFlat( double flatness ) const +{ + // Lines and "begin" segments are flat. + if( + !prev() || + degree() == 1 ) + { + return true; + } + + + // Iterate over control points. + for( unsigned short i = 0; i < degree() - 1; ++i ) + { + if( + height( prev()->knot(), point( i ), knot() ) / chordLength() + >= flatness ) + { + return false; + } + } + + return true; +} + +KoPoint +VSegment::pointAt( double t ) const +{ + KoPoint p; + + pointDerivativesAt( t, &p ); + + return p; +} + +void +VSegment::pointDerivativesAt( double t, KoPoint* p, + KoPoint* d1, KoPoint* d2 ) const +{ + if( !prev() ) + return; + + + // Optimise the line case. + if( degree() == 1 ) + { + const KoPoint diff = knot() - prev()->knot(); + + if( p ) + *p = prev()->knot() + diff * t; + + if( d1 ) + *d1 = diff; + + if( d2 ) + *d2 = KoPoint( 0.0, 0.0 ); + + return; + } + + + // Beziers. + + // Copy points. + KoPoint* q = new KoPoint[ degree() + 1 ]; + + q[ 0 ] = prev()->knot(); + + for( unsigned short i = 0; i < degree(); ++i ) + { + q[ i + 1 ] = point( i ); + } + + + // The De Casteljau algorithm. + for( unsigned short j = 1; j <= degree(); j++ ) + { + for( unsigned short i = 0; i <= degree() - j; i++ ) + { + q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ]; + } + + // Save second derivative now that we have it. + if( j == degree() - 2 ) + { + if( d2 ) + *d2 = degree() * ( degree() - 1 ) + * ( q[ 2 ] - 2 * q[ 1 ] + q[ 0 ] ); + } + + // Save first derivative now that we have it. + else if( j == degree() - 1 ) + { + if( d1 ) + *d1 = degree() * ( q[ 1 ] - q[ 0 ] ); + } + } + + // Save point. + if( p ) + *p = q[ 0 ]; + + delete[]( q ); + + + return; +} + +KoPoint +VSegment::tangentAt( double t ) const +{ + KoPoint tangent; + + pointTangentNormalAt( t, 0L, &tangent ); + + return tangent; +} + +void +VSegment::pointTangentNormalAt( double t, KoPoint* p, + KoPoint* tn, KoPoint* n ) const +{ + // Calculate derivative if necessary. + KoPoint d; + + pointDerivativesAt( t, p, tn || n ? &d : 0L ); + + + // Normalize derivative. + if( tn || n ) + { + const double norm = + sqrt( d.x() * d.x() + d.y() * d.y() ); + + d = norm ? d * ( 1.0 / norm ) : KoPoint( 0.0, 0.0 ); + } + + // Assign tangent vector. + if( tn ) + *tn = d; + + // Calculate normal vector. + if( n ) + { + // Calculate vector product of "binormal" x tangent + // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0). + n->setX( d.y() ); + n->setY( -d.x() ); + } +} + +double +VSegment::length( double t ) const +{ + if( !prev() || t == 0.0 ) + { + return 0.0; + } + + + // Optimise the line case. + if( degree() == 1 ) + { + return + t * chordLength(); + } + + + /* This algortihm is by Jens Gravesen <gravesen AT mat DOT dth DOT dk>. + * We calculate the chord length "chord"=|P0P3| and the length of the control point + * polygon "poly"=|P0P1|+|P1P2|+|P2P3|. The approximation for the bezier length is + * 0.5 * poly + 0.5 * chord. "poly - chord" is a measure for the error. + * We subdivide each segment until the error is smaller than a given tolerance + * and add up the subresults. + */ + + // "Copy segment" splitted at t into a path. + VSubpath path( 0L ); + path.moveTo( prev()->knot() ); + + // Optimize a bit: most of the time we'll need the + // length of the whole segment. + if( t == 1.0 ) + path.append( this->clone() ); + else + { + VSegment* copy = this->clone(); + path.append( copy->splitAt( t ) ); + delete copy; + } + + + double chord; + double poly; + + double length = 0.0; + + while( path.current() ) + { + chord = path.current()->chordLength(); + poly = path.current()->polyLength(); + + if( + poly && + ( poly - chord ) / poly > VGlobal::lengthTolerance ) + { + // Split at midpoint. + path.insert( + path.current()->splitAt( 0.5 ) ); + } + else + { + length += 0.5 * poly + 0.5 * chord; + path.next(); + } + } + + + return length; +} + +double +VSegment::chordLength() const +{ + if( !prev() ) + return 0.0; + + + KoPoint d = knot() - prev()->knot(); + + return sqrt( d * d ); +} + +double +VSegment::polyLength() const +{ + if( !prev() ) + return 0.0; + + + // Start with distance |first point - previous knot|. + KoPoint d = point( 0 ) - prev()->knot(); + + double length = sqrt( d * d ); + + // Iterate over remaining points. + for( unsigned short i = 1; i < degree(); ++i ) + { + d = point( i ) - point( i - 1 ); + length += sqrt( d * d ); + } + + + return length; +} + +double +VSegment::lengthParam( double len ) const +{ + if( + !prev() || + len == 0.0 ) // We divide by len below. + { + return 0.0; + } + + + // Optimise the line case. + if( degree() == 1 ) + { + return + len / chordLength(); + } + + + // Perform a successive interval bisection. + double param1 = 0.0; + double paramMid = 0.5; + double param2 = 1.0; + + double lengthMid = length( paramMid ); + + while( QABS( lengthMid - len ) / len > VGlobal::paramLengthTolerance ) + { + if( lengthMid < len ) + param1 = paramMid; + else + param2 = paramMid; + + paramMid = 0.5 * ( param2 + param1 ); + + lengthMid = length( paramMid ); + } + + return paramMid; +} + +double +VSegment::nearestPointParam( const KoPoint& p ) const +{ + if( !prev() ) + { + return 1.0; + } + + + /* This function solves the "nearest point on curve" problem. That means, it + * calculates the point q (to be precise: it's parameter t) on this segment, which + * is located nearest to the input point P. + * The basic idea is best described (because it is freely available) in "Phoenix: + * An Interactive Curve Design System Based on the Automatic Fitting of + * Hand-Sketched Curves", Philip J. Schneider (Master thesis, University of + * Washington). + * + * For the nearest point q = C(t) on this segment, the first derivative is + * orthogonal to the distance vector "C(t) - P". In other words we are looking for + * solutions of f(t) = ( C(t) - P ) * C'(t) = 0. + * ( C(t) - P ) is a nth degree curve, C'(t) a n-1th degree curve => f(t) is a + * (2n - 1)th degree curve and thus has up to 2n - 1 distinct solutions. + * We solve the problem f(t) = 0 by using something called "Approximate Inversion Method". + * Let's write f(t) explicitly (with c_i = p_i - P and d_j = p_{j+1} - p_j): + * + * n n-1 + * f(t) = SUM c_i * B^n_i(t) * SUM d_j * B^{n-1}_j(t) + * i=0 j=0 + * + * n n-1 + * = SUM SUM w_{ij} * B^{2n-1}_{i+j}(t) + * i=0 j=0 + * + * with w_{ij} = c_i * d_j * z_{ij} and + * + * BinomialCoeff( n, i ) * BinomialCoeff( n - i ,j ) + * z_{ij} = ----------------------------------------------- + * BinomialCoeff( 2n - 1, i + j ) + * + * This Bernstein-Bezier polynom representation can now be solved for it's roots. + */ + + + // Calculate the c_i = point( i ) - P. + KoPoint* c = new KoPoint[ degree() + 1 ]; + + c[ 0 ] = prev()->knot() - p; + + for( unsigned short i = 1; i <= degree(); ++i ) + { + c[ i ] = point( i - 1 ) - p; + } + + + // Calculate the d_j = point( j + 1 ) - point( j ). + KoPoint* d = new KoPoint[ degree() ]; + + d[ 0 ] = point( 0 ) - prev()->knot(); + + for( unsigned short j = 1; j <= degree() - 1; ++j ) + { + d[ j ] = 3.0 * ( point( j ) - point( j - 1 ) ); + } + + + // Calculate the z_{ij}. + double* z = new double[ degree() * ( degree() + 1 ) ]; + + for( unsigned short j = 0; j <= degree() - 1; ++j ) + { + for( unsigned short i = 0; i <= degree(); ++i ) + { + z[ j * ( degree() + 1 ) + i ] = + static_cast<double>( + VGlobal::binomialCoeff( degree(), i ) * + VGlobal::binomialCoeff( degree() - i, j ) ) + / + static_cast<double>( + VGlobal::binomialCoeff( 2 * degree() - 1, i + j ) ); + } + } + + + // Calculate the dot products of c_i and d_i. + double* products = new double[ degree() * ( degree() + 1 ) ]; + + for( unsigned short j = 0; j <= degree() - 1; ++j ) + { + for( unsigned short i = 0; i <= degree(); ++i ) + { + products[ j * ( degree() + 1 ) + i ] = + d[ j ] * c[ i ]; + } + } + + // We don't need the c_i and d_i anymore. + delete[]( d ); + delete[]( c ); + + + // Calculate the control points of the new 2n-1th degree curve. + VSubpath newCurve( 0L ); + newCurve.append( new VSegment( 2 * degree() - 1 ) ); + + // Set up control points in the ( u, f(u) )-plane. + for( unsigned short u = 0; u <= 2 * degree() - 1; ++u ) + { + newCurve.current()->setP( + u, + KoPoint( + static_cast<double>( u ) / static_cast<double>( 2 * degree() - 1 ), + 0.0 ) ); + } + + + // Set f(u)-values. + for( unsigned short k = 0; k <= 2 * degree() - 1; ++k ) + { + unsigned short min = kMin( k, degree() ); + + for( + unsigned short i = kMax( 0, k - ( degree() - 1 ) ); + i <= min; + ++i ) + { + unsigned short j = k - i; + + // p_k += products[j][i] * z[j][i]. + newCurve.getLast()->setP( + k, + KoPoint( + newCurve.getLast()->p( k ).x(), + newCurve.getLast()->p( k ).y() + + products[ j * ( degree() + 1 ) + i ] * + z[ j * ( degree() + 1 ) + i ] ) ); + } + } + + // We don't need the c_i/d_i dot products and the z_{ij} anymore. + delete[]( products ); + delete[]( z ); + +kdDebug(38000) << "results" << endl; +for( int i = 0; i <= 2 * degree() - 1; ++i ) +{ +kdDebug(38000) << newCurve.getLast()->p( i ).x() << " " +<< newCurve.getLast()->p( i ).y() << endl; +} +kdDebug(38000) << endl; + + // Find roots. + QValueList<double> params; + + newCurve.getLast()->rootParams( params ); + + + // Now compare the distances of the candidate points. + double resultParam; + double distanceSquared; + double oldDistanceSquared; + KoPoint dist; + + // First candidate is the previous knot. + dist = prev()->knot() - p; + distanceSquared = dist * dist; + resultParam = 0.0; + + // Iterate over the found candidate params. + for( QValueListConstIterator<double> itr = params.begin(); itr != params.end(); ++itr ) + { + pointDerivativesAt( *itr, &dist ); + dist -= p; + oldDistanceSquared = distanceSquared; + distanceSquared = dist * dist; + + if( distanceSquared < oldDistanceSquared ) + resultParam = *itr; + } + + // Last candidate is the knot. + dist = knot() - p; + oldDistanceSquared = distanceSquared; + distanceSquared = dist * dist; + + if( distanceSquared < oldDistanceSquared ) + resultParam = 1.0; + + + return resultParam; +} + +void +VSegment::rootParams( QValueList<double>& params ) const +{ + if( !prev() ) + { + return; + } + + + // Calculate how often the control polygon crosses the x-axis + // This is the upper limit for the number of roots. + switch( controlPolygonZeros() ) + { + // No solutions. + case 0: + return; + // Exactly one solution. + case 1: + if( isFlat( VGlobal::flatnessTolerance / chordLength() ) ) + { + // Calculate intersection of chord with x-axis. + KoPoint chord = knot() - prev()->knot(); + +kdDebug(38000) << prev()->knot().x() << " " << prev()->knot().y() +<< knot().x() << " " << knot().y() << " ---> " +<< ( chord.x() * prev()->knot().y() - chord.y() * prev()->knot().x() ) / - chord.y() << endl; + params.append( + ( chord.x() * prev()->knot().y() - chord.y() * prev()->knot().x() ) + / - chord.y() ); + + return; + } + break; + } + + // Many solutions. Do recursive midpoint subdivision. + VSubpath path( *this ); + path.insert( path.current()->splitAt( 0.5 ) ); + + path.current()->rootParams( params ); + path.next()->rootParams( params ); +} + +int +VSegment::controlPolygonZeros() const +{ + if( !prev() ) + { + return 0; + } + + + int signChanges = 0; + + int sign = VGlobal::sign( prev()->knot().y() ); + int oldSign; + + for( unsigned short i = 0; i < degree(); ++i ) + { + oldSign = sign; + sign = VGlobal::sign( point( i ).y() ); + + if( sign != oldSign ) + { + ++signChanges; + } + } + + + return signChanges; +} + +bool +VSegment::isSmooth( const VSegment& next ) const +{ + // Return false if this segment is a "begin". + if( !prev() ) + return false; + + + // Calculate tangents. + KoPoint t1; + KoPoint t2; + + pointTangentNormalAt( 1.0, 0L, &t1 ); + + next.pointTangentNormalAt( 0.0, 0L, &t2 ); + + + // Dot product. + if( t1 * t2 >= VGlobal::parallelTolerance ) + return true; + + return false; +} + +KoRect +VSegment::boundingBox() const +{ + // Initialize with knot. + KoRect rect( knot(), knot() ); + + // Add p0, if it exists. + if( prev() ) + { + if( prev()->knot().x() < rect.left() ) + rect.setLeft( prev()->knot().x() ); + + if( prev()->knot().x() > rect.right() ) + rect.setRight( prev()->knot().x() ); + + if( prev()->knot().y() < rect.top() ) + rect.setTop( prev()->knot().y() ); + + if( prev()->knot().y() > rect.bottom() ) + rect.setBottom( prev()->knot().y() ); + } + + if( degree() == 3 ) + { + /* + The basic idea for calculating the axis aligned bounding box (AABB) for bezier segments + was found in comp.graphics.algorithms: + + Both the x coordinate and the y coordinate are polynomial. Newton told + us that at a maximum or minimum the derivative will be zero. Take all + those points, and take the ends; their AABB will be that of the curve. + + We have a helpful trick for the derivatives: use the curve defined by + differences of successive control points. + This is a quadratic Bezier curve: + + 2 + r(t) = Sum Bi,2(t) *Pi = B0,2(t) * P0 + B1,2(t) * P1 + B2,2(t) * P2 + i=0 + + r(t) = (1-t)^2 * P0 + 2t(1-t) * P1 + t^2 * P2 + + r(t) = (P2 - 2*P1 + P0) * t^2 + (2*P1 - 2*P0) * t + P0 + + Setting r(t) to zero and using the x and y coordinates of differences of + successive control points lets us find the paramters t, where the original + bezier curve has a minimum or a maximum. + */ + double t[4]; + + // calcualting the differnces between successive control points + KoPoint x0 = p(1)-p(0); + KoPoint x1 = p(2)-p(1); + KoPoint x2 = p(3)-p(2); + + // calculating the coefficents + KoPoint a = x2 - 2.0*x1 + x0; + KoPoint b = 2.0*x1 - 2.0*x0; + KoPoint c = x0; + + // calculating parameter t at minimum/maximum in x-direction + if( a.x() == 0.0 ) + { + t[0] = - c.x() / b.x(); + t[1] = -1.0; + } + else + { + double rx = b.x()*b.x() - 4.0*a.x()*c.x(); + if( rx < 0.0 ) + rx = 0.0; + t[0] = ( -b.x() + sqrt( rx ) ) / (2.0*a.x()); + t[1] = ( -b.x() - sqrt( rx ) ) / (2.0*a.x()); + } + + // calculating parameter t at minimum/maximum in y-direction + if( a.y() == 0.0 ) + { + t[2] = - c.y() / b.y(); + t[3] = -1.0; + } + else + { + double ry = b.y()*b.y() - 4.0*a.y()*c.y(); + if( ry < 0.0 ) + ry = 0.0; + t[2] = ( -b.y() + sqrt( ry ) ) / (2.0*a.y()); + t[3] = ( -b.y() - sqrt( ry ) ) / (2.0*a.y()); + } + + // calculate points at found minimum/maximum and update bounding box + for( int i = 0; i < 4; ++i ) + { + if( t[i] >= 0.0 && t[i] <= 1.0 ) + { + KoPoint p = pointAt( t[i] ); + + if( p.x() < rect.left() ) + rect.setLeft( p.x() ); + + if( p.x() > rect.right() ) + rect.setRight( p.x() ); + + if( p.y() < rect.top() ) + rect.setTop( p.y() ); + + if( p.y() > rect.bottom() ) + rect.setBottom( p.y() ); + } + } + + return rect; + } + + for( unsigned short i = 0; i < degree() - 1; ++i ) + { + if( point( i ).x() < rect.left() ) + rect.setLeft( point( i ).x() ); + + if( point( i ).x() > rect.right() ) + rect.setRight( point( i ).x() ); + + if( point( i ).y() < rect.top() ) + rect.setTop( point( i ).y() ); + + if( point( i ).y() > rect.bottom() ) + rect.setBottom( point( i ).y() ); + } + + + return rect; +} + +VSegment* +VSegment::splitAt( double t ) +{ + if( !prev() ) + { + return 0L; + } + + + // Create new segment. + VSegment* segment = new VSegment( degree() ); + + // Set segment state. + segment->m_state = m_state; + + + // Lines are easy: no need to modify the current segment. + if( degree() == 1 ) + { + segment->setKnot( + prev()->knot() + + ( knot() - prev()->knot() ) * t ); + + return segment; + } + + + // Beziers. + + // Copy points. + KoPoint* q = new KoPoint[ degree() + 1 ]; + + q[ 0 ] = prev()->knot(); + + for( unsigned short i = 0; i < degree(); ++i ) + { + q[ i + 1 ] = point( i ); + } + + + // The De Casteljau algorithm. + for( unsigned short j = 1; j <= degree(); ++j ) + { + for( unsigned short i = 0; i <= degree() - j; ++i ) + { + q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ]; + } + + // Modify the new segment. + segment->setPoint( j - 1, q[ 0 ] ); + } + + // Modify the current segment (no need to modify the knot though). + for( unsigned short i = 1; i < degree(); ++i ) + { + setPoint( i - 1, q[ i ] ); + } + + + delete[]( q ); + + + return segment; +} + +double +VSegment::height( + const KoPoint& a, + const KoPoint& p, + const KoPoint& b ) +{ + // Calculate determinant of AP and AB to obtain projection of vector AP to + // the orthogonal vector of AB. + const double det = + p.x() * a.y() + b.x() * p.y() - p.x() * b.y() - + a.x() * p.y() + a.x() * b.y() - b.x() * a.y(); + + // Calculate norm = length(AB). + const KoPoint ab = b - a; + const double norm = sqrt( ab * ab ); + + // If norm is very small, simply use distance AP. + if( norm < VGlobal::verySmallNumber ) + return + sqrt( + ( p.x() - a.x() ) * ( p.x() - a.x() ) + + ( p.y() - a.y() ) * ( p.y() - a.y() ) ); + + // Normalize. + return QABS( det ) / norm; +} + +bool +VSegment::linesIntersect( + const KoPoint& a0, + const KoPoint& a1, + const KoPoint& b0, + const KoPoint& b1 ) +{ + const KoPoint delta_a = a1 - a0; + const double det_a = a1.x() * a0.y() - a1.y() * a0.x(); + + const double r_b0 = delta_a.y() * b0.x() - delta_a.x() * b0.y() + det_a; + const double r_b1 = delta_a.y() * b1.x() - delta_a.x() * b1.y() + det_a; + + if( r_b0 != 0.0 && r_b1 != 0.0 && r_b0 * r_b1 > 0.0 ) + return false; + + const KoPoint delta_b = b1 - b0; + + const double det_b = b1.x() * b0.y() - b1.y() * b0.x(); + + const double r_a0 = delta_b.y() * a0.x() - delta_b.x() * a0.y() + det_b; + const double r_a1 = delta_b.y() * a1.x() - delta_b.x() * a1.y() + det_b; + + if( r_a0 != 0.0 && r_a1 != 0.0 && r_a0 * r_a1 > 0.0 ) + return false; + + return true; +} + +bool +VSegment::intersects( const VSegment& segment ) const +{ + if( + !prev() || + !segment.prev() ) + { + return false; + } + + + //TODO: this just dumbs down beziers to lines! + return linesIntersect( segment.prev()->knot(), segment.knot(), prev()->knot(), knot() ); +} + +// TODO: Move this function into "userland" +uint +VSegment::nodeNear( const KoPoint& p, double isNearRange ) const +{ + int index = 0; + + for( unsigned short i = 0; i < degree(); ++i ) + { + if( point( 0 ).isNear( p, isNearRange ) ) + { + index = i + 1; + break; + } + } + + return index; +} + +VSegment* +VSegment::revert() const +{ + if( !prev() ) + return 0L; + + // Create new segment. + VSegment* segment = new VSegment( degree() ); + + segment->m_state = m_state; + + + // Swap points. + for( unsigned short i = 0; i < degree() - 1; ++i ) + { + segment->setPoint( i, point( degree() - 2 - i ) ); + } + + segment->setKnot( prev()->knot() ); + + + // TODO swap node attributes (selected) + + return segment; +} + +VSegment* +VSegment::prev() const +{ + VSegment* segment = m_prev; + + while( segment && segment->state() == deleted ) + { + segment = segment->m_prev; + } + + return segment; +} + +VSegment* +VSegment::next() const +{ + VSegment* segment = m_next; + + while( segment && segment->state() == deleted ) + { + segment = segment->m_next; + } + + return segment; +} + +// TODO: remove this backward compatibility function after koffice 1.3.x +void +VSegment::load( const QDomElement& element ) +{ + if( element.tagName() == "CURVE" ) + { + setDegree( 3 ); + + setPoint( + 0, + KoPoint( + element.attribute( "x1" ).toDouble(), + element.attribute( "y1" ).toDouble() ) ); + + setPoint( + 1, + KoPoint( + element.attribute( "x2" ).toDouble(), + element.attribute( "y2" ).toDouble() ) ); + + setKnot( + KoPoint( + element.attribute( "x3" ).toDouble(), + element.attribute( "y3" ).toDouble() ) ); + } + else if( element.tagName() == "LINE" ) + { + setDegree( 1 ); + + setKnot( + KoPoint( + element.attribute( "x" ).toDouble(), + element.attribute( "y" ).toDouble() ) ); + } + else if( element.tagName() == "MOVE" ) + { + setDegree( 1 ); + + setKnot( + KoPoint( + element.attribute( "x" ).toDouble(), + element.attribute( "y" ).toDouble() ) ); + } +} + +VSegment* +VSegment::clone() const +{ + return new VSegment( *this ); +} + diff --git a/karbon/core/vsegment.h b/karbon/core/vsegment.h new file mode 100644 index 00000000..402946a8 --- /dev/null +++ b/karbon/core/vsegment.h @@ -0,0 +1,432 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSEGMENT_H__ +#define __VSEGMENT_H__ + +#include <qptrlist.h> +#include <qvaluelist.h> + +#include <KoPoint.h> +#include <KoRect.h> + +#include "vglobal.h" +#include <koffice_export.h> + +class QDomElement; +class VPainter; + +/** + * A class representing lines and beziers. We waste some KoPoints, if we + * would use only lines, but this makes it easy to convert the segment types + * into each other. Make sure yourself, that you pass values to functions within + * proper ranges. + */ + +class KARBONBASE_EXPORT VSegment +{ + friend class VSubpath; + friend class VSubpathIterator; + +public: + /** + * Tells which control point is "fixed" i.e. located at the + * corresponding knot and invisible. This flag makes no sense for + * line segments. + */ + enum VCtrlPointFixing + { + none = 0, + first = 1, + second = 2 + }; + + enum VState + { + normal, + deleted + }; + + + VSegment( unsigned short deg = 3 ); + + VSegment( const VSegment& segment ); + + ~VSegment(); + + /** + * Returns the segment's degree, which is identical to the number of nodes. + * For cubic beziers it is "three" and "one" for lines. + */ + unsigned short degree() const + { + return m_degree; + } + + /** + * Sets the segment's degree and thus resizes the array of node data. + * The node data is copied from the old knot "backwards". + */ + void setDegree( unsigned short deg ); + + /** + * Tests for the segment type ("begin", "line" or "curve"). + */ + bool isBegin() const { return (degree() == 1) && !prev(); } + bool isLine() const { return (degree() == 1) && prev(); } + bool isCurve() const { return degree() > 1; } + + /** + * Returns the segment state. + */ + VState state() const + { + return m_state; + } + + /** + * Sets the segment state. + */ + void setState( VState state ) + { + m_state = state; + } + + + /** + * Returns the segment's point with index 0 <= i < degree(). + */ + const KoPoint& point( int i ) const + { + return m_nodes[ i ].m_vector; + } + + /** + * This is a convenience function. It returns the point with index + * 0 <= i <= degree() while p( 0 ) is the knot of the previous + * segment. + */ + const KoPoint& p( int i ) const + { + return i == 0 + ? prev()->knot() + : m_nodes[ --i ].m_vector; + } + + /** + * Returns the knot. This is a convenience function using point(). + */ + const KoPoint& knot() const + { + return point( degree() - 1 ); + } + + /** + * Sets the segment's point with index 0 <= i < degree() to "p". + */ + void setPoint( int i, const KoPoint& p ) + { + m_nodes[ i ].m_vector = p; + } + + /** + * This is a convenience function. It sets the point with index + * 0 <= i <= degree() to "p" while setP( 0 ) sets the knot of the + * previous segment. + */ + void setP( int i, const KoPoint& p ) + { + if( i == 0 ) + prev()->setKnot( p ); + else + m_nodes[ --i ].m_vector = p; + } + + /** + * Sets the knot. This is a convenience function. + */ + void setKnot( const KoPoint& p ) + { + m_nodes[ degree() - 1 ].m_vector = p; + } + + + /** + * Returns true if the point with index 0 <= i < degree() is selected. + */ + bool pointIsSelected( int i ) const + { + return m_nodes[ i ].m_isSelected; + } + + /** + * Returns true if the knot is selected. This is a convenience function. + */ + bool knotIsSelected() const + { + return m_nodes[ degree() - 1 ].m_isSelected; + } + + /** + * Selects the point with index 0 <= i < degree(). + */ + void selectPoint( int i, bool select = true ) + { + m_nodes[ i ].m_isSelected = select; + } + + /** + * Selects/deselects the knot of this segment. + */ + void selectKnot( bool select = true ) + { + m_nodes[ degree() - 1 ].m_isSelected = select; + } + + + /** + * Returns index of the node at point p. Returns 0 if no + * segment point matches point p. + */ + // TODO: Move this function into "userland" + uint nodeNear( const KoPoint& p, + double isNearRange = VGlobal::isNearRange ) const; + + + /** + * Returns a pointer to the previous not deleted segment, if + * stored in a VSubpath. + */ + VSegment* prev() const; + + /** + * Returns a pointer to the next not deleted segment, if + * stored in a VSubpath. + */ + VSegment* next() const; + + /** + * Returns true if the segment is flat. That means it's height + * is smaller than flatness. + */ + bool isFlat( double flatness = VGlobal::flatnessTolerance ) const; + + + /** + * Calculates the point on this segment at parameter 0 <= t <= 1. + * This is a convenience wrapper for pointDerivativesAt(). + */ + KoPoint pointAt( double t ) const; + + /** + * Calculates the point and the derivatives of first and + * second order for 0 <= t <= 1. + */ + void pointDerivativesAt( double t, KoPoint* p = 0L, + KoPoint* d1 = 0L, KoPoint* d2 = 0L ) const; + + + /** + * Calculates the normalized tangent vector (length=1) at the point + * parameterized by 0 <= t <= 1. This is a convenience wrapper + * for pointTangentNormalAt(). Use the latter function directly if you + * need to calculate the point and normal vector or tangent vector + * at once. + */ + KoPoint tangentAt( double t ) const; + + /** + * Calculates the point, the tangent vector and the normal vector for + * 0 <= t <= 1. The tangent vector and the normal vector are + * normalized (length=1). + */ + void pointTangentNormalAt( double t, KoPoint* p = 0L, + KoPoint* tn = 0L, KoPoint* n = 0L ) const; + + + /** + * Calculates the arclength from p0 to the point parametrized + * by 0 <= t <= 1. For beziers this function is a bit expensive. + */ + double length( double t = 1.0 ) const; + + /** + * Calculates the chord length (the distance from the previous + * knot to the current knot). + */ + double chordLength() const; + + /** + * Calculates the length of the control polygon. + */ + double polyLength() const; + + + /** + * Calculates the parameter of a point located at arclength len. + * This is the exact inverse operation of length( t ). + */ + double lengthParam( double len ) const; + + + /** + * Calculates the parameter of the nearest point on this segment + * to the point p. This function is pretty expensive. + */ + double nearestPointParam( const KoPoint& p ) const; + + + /** + * Calculates wether the tangent at the knot is exactly parallel to + * the tangent at p0 of the next segment. Returns false if the + * current segment is a "begin". + */ + bool isSmooth( const VSegment& next ) const; + + bool isSmooth() const + { + return next() + ? isSmooth( *next() ) + : false; + } + + + /** + * Creates a reverted version of this segment. For example: + * if this segment is a line from A to B, the result is a + * line from B to A. + */ + VSegment* revert() const; + + + /** + * Splits the segment at parameter 0 <= t <= 1. Returns a pointer + * to the first segment and modifies the current one to + * be the second segment. + */ + VSegment* splitAt( double t ); + + + /** + * Calculates height of point p above line AB. + */ + static double height( + const KoPoint& a, + const KoPoint& p, + const KoPoint& b ); + + + /** + * Calculates whether lines A0A1 and B0B1 intersect. + */ + static bool linesIntersect( + const KoPoint& a0, + const KoPoint& a1, + const KoPoint& b0, + const KoPoint& b1 ); + + /** + * Returns true, if this segment intersects the other segment. + */ + bool intersects( const VSegment& segment ) const; + + + /** + * Returns a number > 0 if the point p is left, 0 if it's on and + * a number < 0 if it's right of the infinite line through the + * previous segment's knot and the current knot. + */ + double pointIsLeft( const KoPoint& p ) const + { + return + ( knot().x() - prev()->knot().x() ) * + ( p.y() - prev()->knot().y() ) + - + ( p.x() - prev()->knot().x() ) * + ( knot().y() - prev()->knot().y() ); + } + + /** + * Calculates the bounding box. + */ + KoRect boundingBox() const; + + + void draw( VPainter* painter ) const; + + // TODO: remove this backward compatibility function after koffice 1.3.x. + void load( const QDomElement& element ); + + + /** + * Returns a pointer to a copy of this segment. + */ + VSegment* clone() const; + +private: + /** + * Calculates the solutions of y(x) = 0 where 0 <= x <= 1. The + * returned parameters are not ordered. + */ + void rootParams( QValueList<double>& params ) const; + + /** + * Calculates how often the control polygon crosses the x-axis. + */ + int controlPolygonZeros() const; + + + /** + * The segment degree. For (cubic) beziers "three", "one" for lines. + */ + unsigned short m_degree : 6; + + /** + * The segment state. + */ + VState m_state : 2; + + /** + * Node data. + */ + struct VNodeData + { + KoPoint m_vector; + bool m_isSelected; + }; + + /** + * A pointer to an array of node data. + */ + VNodeData* m_nodes; + + + /** + * Pointer to the previous segment. + */ + VSegment* m_prev; + + /** + * Pointer to the next segment. + */ + VSegment* m_next; +}; + +#endif + diff --git a/karbon/core/vselection.cc b/karbon/core/vselection.cc new file mode 100644 index 00000000..ec9626ce --- /dev/null +++ b/karbon/core/vselection.cc @@ -0,0 +1,328 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vdocument.h" +#include "vdrawselection.h" +#include "vpainter.h" +#include "vselection.h" +#include "vselectnodes.h" +#include "vselectobjects.h" +#include "vvisitor.h" +#include "vcolor.h" +#include "vfill.h" +#include "vstroke.h" + +uint VSelection::m_handleNodeSize = 3; + +VSelection::VSelection( VObject* parent ) + : VObject( parent ), m_showhandle( true ) +{ + m_handleRect = new KoRect[ 10 ]; + setStroke( VStroke( VColor( Qt::black ) ) ); + setFill( VFill() ); + + m_selectObjects = true; +} + +VSelection::VSelection( const VSelection& selection ) + : VObject( selection ), VVisitor() +{ + m_handleRect = new KoRect[ 10 ]; + + VObjectListIterator itr = selection.m_objects; + for ( ; itr.current() ; ++itr ) + append( itr.current() ); // Don't clone objects here. + + m_showhandle = true; + m_selectObjects = selection.m_selectObjects; +} + +VSelection::~VSelection() +{ + //clear(); + delete[]( m_handleRect ); +} + +VSelection* +VSelection::clone() const +{ + return new VSelection( *this ); +} + +void +VSelection::accept( VVisitor& visitor ) +{ + visitor.visitVSelection( *this ); +} + +void +VSelection::take( VObject& object ) +{ + m_objects.removeRef( &object ); + if( object.state() >= selected ) + object.setState( normal ); + invalidateBoundingBox(); +} + +bool +VSelection::take( const KoRect& rect, bool selectObjects, bool exclusive ) +{ + bool success = false; + + if( selectObjects ) + { + VSelectObjects op( m_objects, rect, false ); + if( op.visit( *static_cast<VDocument*>( parent() ) ) ) + { + selectNodes(); + success = true; + } + } + else + { + VObjectListIterator itr( m_objects ); + + // Try to deselect all that have at least one node contained in the rect + for ( ; itr.current(); ++itr ) + { + VSelectNodes op( rect, false, exclusive ); + + if( op.visit( *itr.current() ) ) + { + success = true; + } + } + } + + invalidateBoundingBox(); + + return success; +} + +void +VSelection::append() +{ + clear(); + + VSelectObjects op( m_objects ); + op.visit( *static_cast<VDocument*>( parent() ) ); + selectNodes(); + + invalidateBoundingBox(); +} + +void +VSelection::append( VObject* object ) +{ + // only append if item is not deleted or not already in list + if( object->state() != deleted ) + { + if( ! m_objects.containsRef( object ) ) + m_objects.append( object ); + object->setState( selected ); + invalidateBoundingBox(); + } +} + +void +VSelection::append( const VObjectList &objects ) +{ + VObjectListIterator itr = objects; + for( ; itr.current(); ++itr ) + append( itr.current() ); +} + +bool +VSelection::append( const KoRect& rect, bool selectObjects, bool exclusive ) +{ + bool success = false; + + if( selectObjects ) + { + //m_objects.clear(); + VSelectObjects op( m_objects, rect ); + if( op.visit( *static_cast<VDocument*>( parent() ) ) ) + { + selectNodes(); + success = true; + } + } + else + { + VObjectListIterator itr( m_objects ); + VObjectList notSelected; + + // Try to select all that have at least one node contained in the rect + for ( ; itr.current(); ++itr ) + { + VSelectNodes op( rect, true, exclusive ); + + if( op.visit( *itr.current() ) ) + success = true; + else + notSelected.append( itr.current()); + } + // Remove all that were not selected from this selection + VObjectListIterator jtr( notSelected ); + for ( ; jtr.current(); ++jtr ) + take( *( jtr.current() ) ); + } + + invalidateBoundingBox(); + + return success; +} + +void +VSelection::clear() +{ + VSelectNodes op( true ); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + { + op.visit( *itr.current() ); + + //if( itr.current()->state() != deleted ) + // itr.current()->setState( normal ); + } + + m_objects.clear(); + invalidateBoundingBox(); +} + +void +VSelection::draw( VPainter* painter, double zoomFactor ) const +{ + if( objects().count() == 0 || state() == VObject::edit ) + return; + + VDrawSelection op( m_objects, painter, !m_selectObjects, m_handleNodeSize ); + op.visitVSelection( (VSelection &)*this ); + + // get bounding box: + const KoRect& rect = boundingBox(); + + // calculate displaycoords of big handle rect: + m_handleRect[ 0 ].setCoords( qRound( rect.left() ), qRound( rect.top() ), + qRound( rect.right() ), qRound( rect.bottom() ) ); + + KoPoint center = m_handleRect[ 0 ].center(); + + double handleNodeSize = m_handleNodeSize / zoomFactor; + + // calculate displaycoords of nodes: + m_handleRect[ node_lb ].setRect( m_handleRect[0].left() - handleNodeSize, m_handleRect[0].top() - handleNodeSize, 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_mb ].setRect( center.x() - handleNodeSize, m_handleRect[0].top() - handleNodeSize, 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_rb ].setRect( m_handleRect[0].right() - handleNodeSize - (1 / zoomFactor), m_handleRect[0].top() - handleNodeSize, 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_rm ].setRect( m_handleRect[0].right() - handleNodeSize - (1 / zoomFactor), center.y() - handleNodeSize, 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_rt ].setRect( m_handleRect[0].right() - handleNodeSize - (1 / zoomFactor) , m_handleRect[0].bottom() - handleNodeSize - (1 / zoomFactor), 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_mt ].setRect( center.x() - handleNodeSize, m_handleRect[0].bottom() - handleNodeSize - (1 / zoomFactor), 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_lt ].setRect( m_handleRect[0].left() - handleNodeSize, m_handleRect[0].bottom() - handleNodeSize - (1 / zoomFactor), 2 * handleNodeSize, 2 * handleNodeSize ); + m_handleRect[ node_lm ].setRect( m_handleRect[0].left() - handleNodeSize, center.y() - handleNodeSize, 2 * handleNodeSize, 2 * handleNodeSize ); + + if( !m_showhandle ) return; + + // draw handle rect: + painter->setPen( Qt::blue.light() ); + painter->setBrush( Qt::NoBrush ); + + painter->drawRect( KoRect( m_handleRect[ 0 ].x() * zoomFactor, m_handleRect[ 0 ].y() * zoomFactor, + m_handleRect[ 0 ].width() * zoomFactor, m_handleRect[ 0 ].height() * zoomFactor ) ); + painter->setPen( Qt::blue.light() ); + + // draw nodes: + if( state() == VObject::selected ) + { + painter->setPen( Qt::blue.light() ); + painter->setBrush( Qt::white ); + + KoRect temp; + for( uint i = node_lt; i <= node_rb; ++i ) + { + if( i != node_mm ) + { + temp.setRect( zoomFactor * m_handleRect[ i ].left(), + zoomFactor * m_handleRect[ i ].top(), + 2 * m_handleNodeSize + 1, 2 * m_handleNodeSize + 1 ); + painter->drawRect( temp ); + } + } + } +} + +const KoRect& +VSelection::boundingBox() const +{ +// disable bbox caching for selection since there is no reliable +// way to get notified of a bbox change: +// if( m_boundingBoxIsInvalid ) +// { + // clear: + m_boundingBox = KoRect(); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + m_boundingBox |= itr.current()->boundingBox(); + +// m_boundingBoxIsInvalid = false; +// } + + return m_boundingBox; +} + + +VHandleNode +VSelection::handleNode( const KoPoint &point ) const +{ + for( uint i = node_lt; i <= node_rb; ++i ) + { + if( m_handleRect[i].contains( point ) ) + return static_cast<VHandleNode>( i ); + } + + return node_none; +} + +QPtrList<VSegment> +VSelection::getSegments( const KoRect& rect ) +{ + VTestNodes op( rect ); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + op.visit( *itr.current() ); + + return op.result(); +} + +void +VSelection::selectNodes( bool select ) +{ + VSelectNodes op( select ); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + { + op.visit( *itr.current() ); + } +} + diff --git a/karbon/core/vselection.h b/karbon/core/vselection.h new file mode 100644 index 00000000..31dbb266 --- /dev/null +++ b/karbon/core/vselection.h @@ -0,0 +1,209 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTION_H__ +#define __VSELECTION_H__ + + +#include <qptrlist.h> + +#include <KoRect.h> + +#include "vobject.h" +#include "vvisitor.h" +#include <koffice_export.h> +class KoPoint; +class QObject; +class VPainter; +class VVisitor; +class VSegment; + +typedef QPtrList<VObject> VObjectList; +typedef QPtrListIterator<VObject> VObjectListIterator; + + +/// Ids of manipulation nodes. +enum VHandleNode +{ + node_none = 0, + node_lt = 1, + node_mt = 2, + node_rt = 3, + node_lm = 4, + node_mm = 5, + node_rm = 6, + node_lb = 7, + node_mb = 8, + node_rb = 9 +}; + + +/** + * VSelection manages a set of selected vobjects. + */ +class KARBONBASE_EXPORT VSelection : public VObject, public VVisitor +{ +public: + /** + * Constructs a vselection with the specified parent. + * + * @param parent the selection's parent + */ + VSelection( VObject* parent = 0L ); + + /** + * Constructs a vselection by copying the specified selection. + * + * @param selection the selection to copy from + */ + VSelection( const VSelection& selection ); + + /** + * Destroys the selection. + */ + virtual ~VSelection(); + + /** + * Paint selected objects outline and handle. + */ + void draw( VPainter* painter, double zoomFactor ) const; + + virtual const KoRect& boundingBox() const; + + virtual VSelection* clone() const; + + virtual void accept( VVisitor& visitor ); + + /** + * Adds all objects to the selection. + */ + void append(); + + /** + * Adds an object to the selection. + */ + void append( VObject* object ); + + /** + * Adds all objects of the specified object list to the selection. + * + * @param objects the list of objects to add + */ + void append( const VObjectList &objects ); + + /** + * Adds all objects ( selectObjects == true ) or all nodes + * ( selectObjects == false ) within rect to the selection. + */ + bool append( const KoRect& rect, bool selectObjects = true, bool exclusive = true ); + + /** + * Removes the reference to the object, not the object itself. + */ + void take( VObject& object ); + + /** + * Removes all objects ( selectObjects == true ) or all nodes + * ( selectObjects == false ) within rect from the selection. + */ + bool take( const KoRect& rect, bool selectObjects = true, bool exclusive = true ); + + /** + * Removes the references to all objects, not the objects themselves. + */ + void clear(); + + /** + * Read only access to the selected objects. + */ + const VObjectList& objects() const { return m_objects; } + + /** + * Returns a list of segments that have at least one control point inside the specified rect. + * + * @param rect the selection rect + * @return the list of segments + */ + QPtrList<VSegment> getSegments( const KoRect& rect ); + + /** + * Selects or deselects all nodes. + * + * @param select controls if nodes are selected or deselected + */ + void selectNodes( bool select = true ); + + /** + * Returns the handle node id, the KoPoint is inside. + * + * @param point the selection point + * @return the handle the point is inside or node_none if point is not inside any node + */ + VHandleNode handleNode( const KoPoint &point ) const; + + /** + * Toggle selection handles on/off. + * + * @param handle controls if handle are shown or not + */ + void showHandle( bool handle = true ) { m_showhandle = handle; } + + /** + * Toggles selection of objects/nodes. + * + * @param selectObjects controls if objects or nodes are selected + */ + virtual void setSelectObjects( bool selectObjects = true ) { m_selectObjects = selectObjects; } + + static void setHandleSize( uint size ) + { m_handleNodeSize = size; } + + static uint handleSize() + { return m_handleNodeSize; } +private: + /** + * Show/Hide handle. + */ + bool m_showhandle; + + /** + * Select objects and not nodes? + */ + bool m_selectObjects; + + /** + * The list of currently selected objects. + */ + VObjectList m_objects; + + /** + * Paint coordinates of handle rectangle and handle nodes. + * Used for handle node determination and handle node drawing. + */ + KoRect *m_handleRect; + + /** + * Paint size of nodes. + */ + static uint m_handleNodeSize; +}; + +#endif + diff --git a/karbon/core/vstroke.cc b/karbon/core/vstroke.cc new file mode 100644 index 00000000..b7431be5 --- /dev/null +++ b/karbon/core/vstroke.cc @@ -0,0 +1,265 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> + +#include <KoGenStyles.h> +#include <KoStyleStack.h> +#include <KoUnit.h> +#include <KoXmlNS.h> + +#include "vobject.h" +#include "vstroke.h" +#include <kdebug.h> + +VStroke::VStroke() +: m_parent(0L), m_lineWidth(1.0), m_lineCap(capButt), m_lineJoin(joinMiter), m_miterLimit(10.0), m_type(none) +{} + +VStroke::VStroke( VObject* parent, float width, const VLineCap cap, const VLineJoin join, + float miterLimit ) +{ + m_parent = parent; + m_type = solid; + m_lineWidth = width; + m_lineCap = cap; + m_lineJoin = join; + m_miterLimit = miterLimit; +} + +VStroke::VStroke( const VColor &c, VObject* parent, float width, const VLineCap cap, const VLineJoin join, + float miterLimit ) +{ + m_parent = parent; + m_type = solid; + m_lineWidth = width; + m_lineCap = cap; + m_lineJoin = join; + m_miterLimit = miterLimit; + m_color = c; +} + +VStroke::VStroke( const VStroke& stroke ) +{ + // doesn't copy parent: + *this = stroke; +} + +void +VStroke::setLineWidth( float width ) +{ + m_lineWidth = width; + + // tell our parent so he can update his bbox: + if( m_parent ) + m_parent->invalidateBoundingBox(); +} + +void +VStroke::save( QDomElement& element ) const +{ + QDomElement me = element.ownerDocument().createElement( "STROKE" ); + element.appendChild( me ); + + // save stroke parameters: + if( m_lineWidth != 1.0 ) + me.setAttribute( "lineWidth", m_lineWidth ); + if( !( m_lineCap == capButt ) ) + me.setAttribute( "lineCap", m_lineCap ); + if( !( m_lineJoin == joinMiter ) ) + me.setAttribute( "lineJoin", m_lineJoin ); + if( m_miterLimit != 10.0 ) + me.setAttribute( "miterLimit", m_miterLimit ); + + if( m_type == solid ) + { + // save color: + m_color.save( me ); + } + else if( m_type == grad ) + { + // save gradient: + m_gradient.save( me ); + } + else if( m_type == patt ) + { + // save pattern: + m_pattern.save( me ); + } + + // save dashpattern: + m_dashPattern.save( me ); +} + +void +VStroke::saveOasis( KoGenStyle &style ) const +{ + if( m_type == solid ) + { + style.addProperty( "draw:stroke", "solid" ); + style.addProperty( "svg:stroke-color", QColor( m_color ).name() ); + style.addPropertyPt( "svg:stroke-width", m_lineWidth ); + if( m_color.opacity() < 1 ) + style.addProperty( "svg:stroke-opacity", QString( "%1%" ).arg( m_color.opacity() * 100. ) ); + } + else if( m_type == none ) + style.addProperty( "draw:stroke", "none" ); + /*else if( m_type == grad ) + style.addProperty( "draw:stroke", "gradient" ); + else if( m_type == patt ) + style.addProperty( "draw:stroke", "hatch" );*/ + + if( m_lineJoin == joinRound ) + style.addProperty( "draw:stroke-linejoin", "round" ); + else if( m_lineJoin == joinBevel ) + style.addProperty( "draw:stroke-linejoin", "bevel" ); + else if( m_lineJoin == joinMiter ) + style.addProperty( "draw:stroke-linejoin", "miter" ); +} + +void +VStroke::loadOasis( const KoStyleStack &stack ) +{ + if( stack.hasAttributeNS( KoXmlNS::draw, "stroke" )) + { + if( stack.attributeNS( KoXmlNS::draw, "stroke" ) == "solid" ) + { + setType( VStroke::solid ); + setColor( QColor( stack.attributeNS( KoXmlNS::svg, "stroke-color" ) ) ); + if( stack.hasAttributeNS( KoXmlNS::svg, "stroke-opacity" ) ) + m_color.setOpacity( stack.attributeNS( KoXmlNS::svg, "stroke-opacity" ).remove( '%' ).toFloat() / 100. ); + QString join = stack.attributeNS( KoXmlNS::draw, "stroke-linejoin" ); + if( !join.isEmpty() ) + { + if( join == "round" ) + m_lineJoin = joinRound; + else if( join == "bevel" ) + m_lineJoin = joinBevel; + else + m_lineJoin = joinMiter; + } + } + else if( stack.attributeNS( KoXmlNS::draw, "stroke" ) == "none" ) + setType( VStroke::none ); + } + if( stack.hasAttributeNS( KoXmlNS::svg, "stroke-width" ) ) + m_lineWidth = KoUnit::parseValue( stack.attributeNS( KoXmlNS::svg, "stroke-width" ) ); + if( m_lineWidth < 0.0 ) + m_lineWidth = 0.0; +} + +void +VStroke::load( const QDomElement& element ) +{ + m_type = none; + // load stroke parameters: + m_lineWidth = element.attribute( "lineWidth", "1.0" ).toDouble(); + if( m_lineWidth < 0.0 ) + m_lineWidth = 0.0; + + switch( element.attribute( "lineCap", "0" ).toUShort() ) + { + case 1: + m_lineCap = capRound; break; + case 2: + m_lineCap = capSquare; break; + default: + m_lineCap = capButt; + } + + switch( element.attribute( "lineJoin", "0" ).toUShort() ) + { + case 1: + m_lineJoin = joinRound; break; + case 2: + m_lineJoin = joinBevel; break; + default: + m_lineJoin = joinMiter; + } + + m_miterLimit = element.attribute( "miterLimit", "10.0" ).toDouble(); + if( m_miterLimit < 0.0 ) + m_miterLimit = 0.0; + + + // load color: + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + QDomElement e = list.item( i ).toElement(); + if( e.tagName() == "COLOR" ) + { + m_color.load( e ); + m_type = solid; + } + else if( e.tagName() == "DASHPATTERN" ) + { + m_dashPattern.load( e ); + } + else if( e.tagName() == "GRADIENT" ) + { + m_type = grad; + m_gradient.load( e ); + } + else if( e.tagName() == "PATTERN" ) + { + m_type = patt; + m_pattern.load( e ); + } + } + } +} + + +VStroke& +VStroke::operator=( const VStroke& stroke ) +{ + if( this != &stroke ) + { + // dont copy the parent! + m_type = stroke.m_type; + + m_lineWidth = stroke.m_lineWidth; + // Tell our parent about the linewidth change, so he can update his bbox: + //if( m_parent ) + // m_parent->invalidateBoundingBox(); + + m_lineCap = stroke.m_lineCap; + m_lineJoin = stroke.m_lineJoin; + m_miterLimit = stroke.m_miterLimit; + m_color = stroke.m_color; + m_dashPattern = stroke.m_dashPattern; + m_gradient = stroke.m_gradient; + m_pattern = stroke.m_pattern; + } + + return *this; +} + +void +VStroke::transform( const QWMatrix& m ) +{ + if( type() == VStroke::grad ) + gradient().transform( m ); + else if( type() == VStroke::patt ) + pattern().transform( m ); +} diff --git a/karbon/core/vstroke.h b/karbon/core/vstroke.h new file mode 100644 index 00000000..6cfa338d --- /dev/null +++ b/karbon/core/vstroke.h @@ -0,0 +1,135 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTROKE_H__ +#define __VSTROKE_H__ + +#include <qvaluelist.h> + +#include "vcolor.h" +#include "vdashpattern.h" +#include "vgradient.h" +#include "vpattern.h" +#include <koffice_export.h> + +class QDomElement; +class VObject; +class KoGenStyle; +class KoStyleStack; + + +/** + * Manages stroke properties. + * Supported are line join/cap styles equivalents to the qpainter ones. + * Also the line width in pixels and line stroke type (solid / gradient). + * Finally it also managed the dashing pattern, see VDashPattern. + * + * Default is black solid outline of width 1 with miter join, butt cap + * style and no dashes. + */ + +class KARBONBASE_EXPORT VStroke +{ +public: + enum VStrokeType + { + none = 0, /// no stroke at all + solid = 1, /// solid stroke + grad = 2, /// gradient as stroke + patt = 3, /// pattern as stroke + unknown = 4 + }; + + enum VLineCap + { + capButt = 0, + capRound = 1, + capSquare = 2 + }; + + enum VLineJoin + { + joinMiter = 0, + joinRound = 1, + joinBevel = 2 + }; + + VStroke(); + VStroke( VObject* parent, float width = 1.0, const VLineCap cap = capButt, + const VLineJoin join = joinMiter, float miterLimit = 10.0 ); + VStroke( const VColor &c, VObject* parent = 0L, float width = 1.0, const VLineCap cap = capButt, + const VLineJoin join = joinMiter, float miterLimit = 10.0 ); + VStroke( const VStroke& stroke ); + + void setParent( VObject* parent ) { m_parent = parent; } + VObject* parent()const { return m_parent; } + + VStrokeType type() const { return m_type; } + void setType( VStrokeType type ) { m_type = type; } + + const VColor& color() const { return m_color; } + void setColor( const VColor& color ) { m_color = color; } + + float lineWidth() const { return m_lineWidth; } + void setLineWidth( float width ); + + VLineCap lineCap() const { return m_lineCap; } + void setLineCap( VLineCap cap ) { m_lineCap = cap; } + + VLineJoin lineJoin() const { return m_lineJoin; } + void setLineJoin( VLineJoin join ) { m_lineJoin = join; } + + float miterLimit() const { return m_miterLimit; } + void setMiterLimit( float limit ) { m_miterLimit = limit; } + + VGradient& gradient() { return m_gradient; } + const VGradient& gradient() const { return m_gradient; } + + VPattern& pattern() { return m_pattern; } + const VPattern& pattern() const { return m_pattern; } + + VDashPattern& dashPattern() { return m_dashPattern; } + const VDashPattern& dashPattern() const { return m_dashPattern; } + + void save( QDomElement& element ) const; + void saveOasis( KoGenStyle &style ) const; + void load( const QDomElement& element ); + void loadOasis( const KoStyleStack &stack ); + + + VStroke& operator=( const VStroke& stroke ); + + void transform( const QWMatrix& m ); + +private: + VObject *m_parent; + + VColor m_color; + VGradient m_gradient; + VPattern m_pattern; + float m_lineWidth; + float m_miterLimit; + VLineCap m_lineCap : 2; + VLineJoin m_lineJoin : 2; + VStrokeType m_type : 3; + VDashPattern m_dashPattern; +}; + +#endif diff --git a/karbon/core/vtext.cc b/karbon/core/vtext.cc new file mode 100644 index 00000000..53c6af51 --- /dev/null +++ b/karbon/core/vtext.cc @@ -0,0 +1,745 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdom.h> +#include <qfile.h> + +#include <kdebug.h> +#include <KoPoint.h> +#include <KoRect.h> + +#include "vpath.h" +#include "vtext.h" +#include "vtext_iface.h" +#include "vstroke.h" +#include "vfill.h" +#include "vvisitor.h" +#include "vsegment.h" +#include "vgroup.h" +#include "vpainter.h" +#include "commands/vtransformcmd.h" + +#ifdef HAVE_KARBONTEXT + +#include <ft2build.h> +#include <fontconfig/fontconfig.h> + + +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_GLYPH_H + +#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0)) +#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5)) + + +// Trace routines for ttf / ps font -> VSubpath + +int traceMoveto( FT_Vector *to, VPath *composite ) +{ + double tox = ( to->x / 64.0 ); + double toy = ( -to->y / 64.0 ); + + //QString add = "M" + QString::number(tox) + "," + QString::number(toy) + " "; + //kdDebug(38000) << add.latin1() << endl; + composite->moveTo( KoPoint( tox, toy ) ); + + return 0; +} + +int traceLineto( FT_Vector *to, VPath *composite ) +{ + double tox = ( to->x / 64.0 ); + double toy = ( -to->y / 64.0 ); + + //QString add = "L" + QString::number(tox) + "," + QString::number(toy) + " "; + //kdDebug(38000) << add.latin1() << endl; + + composite->lineTo( KoPoint( tox, toy ) ); + + return 0; +} + +int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, VPath *composite ) +{ + double x1 = ( control->x / 64.0 ); + double y1 = ( -control->y / 64.0 ); + double x2 = ( to->x / 64.0 ); + double y2 = ( -to->y / 64.0 ); + + //QString add = "Q" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::number(y2) + " "; + //kdDebug(38000) << add.latin1() << endl; + composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x2, y2 ) ); + //composite->curve2To( KoPoint( x1, y1 ), KoPoint( x2, y2 ) ); + + return 0; +} + +int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, VPath *composite ) +{ + double x1 = ( p->x / 64.0 ); + double y1 = ( -p->y / 64.0 ); + double x2 = ( q->x / 64.0 ); + double y2 = ( -q->y / 64.0 ); + double x3 = ( to->x / 64.0 ); + double y3 = ( -to->y / 64.0 ); + + //QString add = "C" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::number(y2) + "," + QString::number(x3) + "," + QString::number(y3); + //kdDebug(38000) << add.latin1() << endl; + + composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x3, y3 ) ); + + return 0; +} + +FT_Outline_Funcs OutlineMethods = +{ + (FT_Outline_MoveTo_Func) traceMoveto, + (FT_Outline_LineTo_Func) traceLineto, + (FT_Outline_ConicTo_Func) traceQuadraticBezier, + (FT_Outline_CubicTo_Func) traceCubicBezier, + 0, + 0 +}; + +#endif // HAVE_KARBONTEXT + +VText::VText( VObject* parent, VState state ) + : VObject( parent, state ), m_basePath( 0L ) +{ + m_glyphs.setAutoDelete( true ); + m_boundingBoxIsInvalid = true; + m_stroke = new VStroke( this ); + m_fill = new VFill(); + m_position = (VText::Position)0; + m_alignment = (VText::Alignment)0; + m_shadow = false; + m_translucentShadow = false; + m_shadowAngle = 0; + m_shadowDistance = 0; + m_offset = 0.0; +} + + +VText::VText( const QFont &font, const VSubpath& basePath, Position position, Alignment alignment, const QString& text ) + : VObject( 0L ), m_font( font ), m_basePath( basePath ), m_position( position ), m_alignment( alignment ), m_text( text ) +{ + m_glyphs.setAutoDelete( true ); + m_boundingBoxIsInvalid = true; + m_stroke = new VStroke( this ); + m_fill = new VFill(); + m_offset = 0.0; +} + +VText::VText( const VText& text ) + : VObject( text ), m_font( text.m_font ), m_basePath( text.m_basePath ), m_position( text.m_position ), m_alignment( text.m_alignment ), m_text( text.m_text ), m_shadow( text.m_shadow ), m_translucentShadow( text.m_translucentShadow ), m_shadowDistance( text.m_shadowDistance ), m_shadowAngle( text.m_shadowAngle ), m_offset( text.m_offset ) +{ + m_stroke = new VStroke( *text.m_stroke ); + m_stroke->setParent( this ); + m_fill = new VFill( *text.m_fill ); + + // copy glyphs + VPathListIterator itr( text.m_glyphs ); + for( ; itr.current() ; ++itr ) + { + VPath* c = itr.current()->clone(); + c->setParent( this ); + m_glyphs.append( c ); + } + + m_boundingBoxIsInvalid = true; +} + +VText::~VText() +{ +} + +DCOPObject* VText::dcopObject() +{ + if( !m_dcop ) + m_dcop = new VTextIface( this ); + + return m_dcop; +} + + +void +VText::draw( VPainter* painter, const KoRect* /*rect*/ ) const +{ + if( + state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + painter->save(); + + VPathListIterator itr( m_glyphs ); + + if( state() != edit ) + { + // paint fill: + painter->newPath(); + + if ( m_shadow ) + { + VColor color; + if ( m_translucentShadow ) + { + color.set( 0., 0., 0. ); + color.setOpacity( .3 ); + } + else + { + color.set( .3, .3, .3 ); + color.setOpacity( 1. ); + } + int shadowDx = int( m_shadowDistance * cos( m_shadowAngle / 360. * 6.2832 ) ); + int shadowDy = int( m_shadowDistance * sin( m_shadowAngle / 360. * 6.2832 ) ); + + VTransformCmd trafo( 0L, QWMatrix() ); + for( itr.toFirst(); itr.current(); ++itr ) + { + trafo.setMatrix( QWMatrix( 1, 0, 0, 1, shadowDx, shadowDy ) ); + trafo.visit( *( itr.current() ) ); + itr.current()->setFill( VFill( color ) ); + itr.current()->setStroke( VStroke( color ) ); + itr.current()->draw( painter ); + trafo.setMatrix( QWMatrix( 1, 0, 0, 1, -shadowDx, -shadowDy ) ); + trafo.visit( *( itr.current() ) ); + } + } + + for( itr.toFirst(); itr.current(); ++itr ) + { + itr.current()->setFill( *m_fill ); + itr.current()->setStroke( *m_stroke ); + itr.current()->draw( painter ); + } + } + + // draw simplistic contour: + if( state() == edit )//|| state() == selected ) + { + painter->newPath(); + painter->setRasterOp( Qt::XorROP ); + painter->setPen( Qt::yellow ); + painter->setBrush( Qt::NoBrush ); + + for( itr.toFirst(); itr.current(); ++itr ) + itr.current()->draw( painter ); + + painter->strokePath(); + } + + painter->restore(); +} + +const KoRect& +VText::boundingBox() const +{ + if( m_boundingBoxIsInvalid ) + { + VPathListIterator itr( m_glyphs ); + itr.toFirst(); + // clear: + m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect(); + for( ++itr; itr.current(); ++itr ) + if( !itr.current()->boundingBox().isEmpty() ) + m_boundingBox |= itr.current()->boundingBox(); + + // take line width into account: + m_boundingBox.setCoords( + m_boundingBox.left() - 0.5 * stroke()->lineWidth(), + m_boundingBox.top() - 0.5 * stroke()->lineWidth(), + m_boundingBox.right() + 0.5 * stroke()->lineWidth(), + m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() ); + + m_boundingBoxIsInvalid = false; + } + + return m_boundingBox; +} + +VText* +VText::clone() const +{ + return new VText( *this ); +} + +VGroup* VText::toVGroup() const +{ + VGroup* group = new VGroup( parent() ); + + VPathListIterator itr( m_glyphs ); + for( itr.toFirst(); itr.current(); ++itr ) + { + VPath* c = itr.current()->clone(); + c->setParent( group ); + group->append( c ); + } + + group->setFill( *m_fill ); + group->setStroke( *m_stroke ); + + return group; +} // VText::toVGroup + +void +VText::save( QDomElement& element ) const +{ + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "TEXT" ); + + VPath path( 0L ); + path.combinePath( m_basePath ); + path.save( me ); + + VObject::save( me ); + + // save font properties + me.setAttribute( "text", m_text ); + me.setAttribute( "family", m_font.family() ); + me.setAttribute( "size", m_font.pointSize() ); + me.setAttribute( "italic", m_font.italic() ); + me.setAttribute( "bold", m_font.bold() ); + me.setAttribute( "position", m_position ); + me.setAttribute( "alignment", m_alignment ); + me.setAttribute( "shadow", m_shadow ); + me.setAttribute( "translucentshadow", m_translucentShadow ); + me.setAttribute( "shadowangle", m_shadowAngle ); + me.setAttribute( "shadowdist", m_shadowDistance ); + me.setAttribute( "offset", m_offset ); + element.appendChild( me ); + + // save all glyphs / paths + VPathListIterator itr = m_glyphs; + for( itr.toFirst(); itr.current(); ++itr ) + itr.current()->save( me ); + } +} + +void +VText::load( const QDomElement& element ) +{ + m_glyphs.clear(); + + m_font.setFamily( element.attribute( "family", "Times" ) ); + m_font.setPointSize( element.attribute( "size", "12" ).toInt() ); + m_font.setItalic( element.attribute( "italic" ).toInt() == 1 ); + m_font.setWeight( QFont::Normal ); + m_font.setBold( element.attribute( "bold" ).toInt() == 1 ); + m_position = (Position)element.attribute( "position", "0" ).toInt(); + m_alignment = (Alignment)element.attribute( "alignment", "0" ).toInt(); + m_shadow = ( element.attribute( "shadow" ).toInt() == 1 ); + m_translucentShadow = ( element.attribute( "translucentshadow" ).toInt() == 1 ); + m_shadowAngle = element.attribute( "shadowangle" ).toInt(); + m_shadowDistance = element.attribute( "shadowdist" ).toInt(); + m_offset = element.attribute( "offset" ).toDouble(); + m_text = element.attribute( "text", "" ); + + VObject::load( element ); + + QDomNodeList list = element.childNodes(); + QDomElement e = list.item( 0 ).toElement(); + + // element to start with reading glyph paths and stroke, fill, etc. + uint startElement = 0; + + if( e.tagName() == "PATH" ) + { + VPath path( 0L ); + path.load( e ); + m_basePath = *path.paths().getFirst(); + startElement++; + } + + // load text glyphs: + for( uint i = startElement; i < list.count(); ++i ) + { + if( list.item( i ).isElement() ) + { + e = list.item( i ).toElement(); + if( e.tagName() == "PATH" ) + { + VPath *composite = new VPath( this ); + composite->load( e ); + m_glyphs.append( composite ); + } + if( e.tagName() == "STROKE" ) + m_stroke->load( e ); + if( e.tagName() == "FILL" ) + m_fill->load( e ); + } + } + // if no glyphs yet, trace them +#ifdef HAVE_KARBONTEXT + if( m_glyphs.count() == 0 ) + traceText(); +#endif + m_boundingBoxIsInvalid = true; + //m_fill->setFillRule( VFill::evenOdd ); +} + +void +VText::setText( const QString& text ) +{ + if( m_text != text ) + { + m_text = text; + m_glyphs.clear(); +#ifdef HAVE_KARBONTEXT + traceText(); +#endif + } +} + +void +VText::setState( const VState state ) +{ + VObject::setState( state ); + + VPathListIterator itr( m_glyphs ); + for( itr.toFirst(); itr.current(); ++itr ) + { + itr.current()->setState( state ); + } +} + +void +VText::accept( VVisitor& visitor ) +{ + visitor.visitVText( *this ); +} + +#ifdef HAVE_KARBONTEXT + +void +VText::traceText() +{ + if( m_basePath.count() == 0 ) + { + kdDebug(38000) << "Can't draw a text without base path (was: " << m_text << ")." << endl; + return; + } + + // TODO : set more options + int slant = FC_SLANT_ROMAN; + if( m_font.italic() ) + slant = FC_SLANT_ITALIC; + + int weight = 0; + if( m_font.bold() ) + weight = FC_WEIGHT_BOLD; + + // Build FontConfig request pattern + int id = -1; + QString filename = buildRequest( m_font.family(), weight, slant, m_font.pointSize(), id ); + m_glyphs.clear(); + + kdDebug(38000) << "Loading " << filename.latin1() << " for requested font \"" << m_font.family().latin1() << "\", " << m_font.pointSize() << " pt." << endl; + + FT_UInt glyphIndex; + FT_Face fontFace; + // TODO : this lib should probably be a singleton (Rob) + FT_Library library; + FT_Init_FreeType( &library ); + FT_Error error = FT_New_Face( library, QFile::encodeName(filename), id, &fontFace ); + + if( error ) + { + kdDebug(38000) << "traceText(), could not load font. Aborting!" << endl; + return; + } + + bool foundCharmap = false; + + // Try to choose unicode charmap + for( int charmap = 0; charmap < fontFace->num_charmaps; charmap++ ) + { + if( fontFace->charmaps[charmap]->encoding == ft_encoding_unicode ) + { + FT_Error error = FT_Set_Charmap( fontFace, fontFace->charmaps[charmap] ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to select unicode charmap." << endl; + continue; + } + foundCharmap = true; + } + } + + // Choose first charmap if no unicode charmap was found + if( ! foundCharmap ) + { + error = FT_Set_Charmap( fontFace, fontFace->charmaps[0] ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to select charmap. Aborting!" << endl; + FT_Done_Face( fontFace ); + FT_Done_FreeType( library ); + return; + } + } + + error = FT_Set_Char_Size( fontFace, FT_FROMFLOAT( m_font.pointSize() ), FT_FROMFLOAT( m_font.pointSize() ), 0, 0 ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to set font size. Aborting!" << endl; + FT_Done_Face( fontFace ); + FT_Done_FreeType( library ); + return; + } + + // storing glyphs. + float l = 0; + QValueList<float> glyphXAdvance; + QValueList<float> glyphYAdvance; + for( unsigned int i = 0; i < m_text.length(); i++ ) + { + // get the glyph index for the current character + QChar character = m_text.at( i ); + glyphIndex = FT_Get_Char_Index( fontFace, character.unicode() ); + if( ! glyphIndex ) + { + kdDebug(38000) << "traceText(), unable get index of char : " << character << endl; + continue; + } + //kdDebug(38000) << "glyphIndex : " << glyphIndex << endl; + FT_Error error = FT_Load_Glyph( fontFace, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to load glyph : " << error << endl; + continue; + } + + // decompose to vpaths + FT_OutlineGlyph g; + error = FT_Get_Glyph( fontFace->glyph, reinterpret_cast<FT_Glyph *>( &g ) ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to get glyph: " << error << endl; + continue; + } + + VPath *composite = new VPath( this ); + error = FT_Outline_Check( &g->outline ); + if( error ) + { + kdDebug(38000) << "traceText(), outline is broken : " << error << endl; + continue; + } + + error = FT_Outline_Decompose(&g->outline, &OutlineMethods, composite ); + if( error ) + { + kdDebug(38000) << "traceText(), unable to decompose outline : " << error << endl; + continue; + } + + m_glyphs.append( composite ); + glyphXAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.x ) ); + glyphYAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.y ) ); + l += FT_TOFLOAT( fontFace->glyph->advance.x ); + FT_Done_Glyph( reinterpret_cast<FT_Glyph>( g ) ); + } + + // Placing the stored glyphs. + float pathLength = 0; + VSubpathIterator pIt( m_basePath ); + + VSegment* seg; + for( ; pIt.current(); ++pIt ) + if( (seg = pIt.current() ) ) + pathLength += seg->length(); + + kdDebug(38000) << "traceText(), using offset : " << m_offset << endl; + float x = m_offset * pathLength; + + switch( m_alignment ) + { + case Left: x += 0; break; + case Center: x -= 0.5 * l; break; + case Right: x -= l; break; + } + float y = 0; + float dx = 0; + float sp = 0; + KoPoint point; + KoPoint normal; + KoPoint tangent; + VSubpathIterator pathIt( m_basePath ); + VSegment* oldSeg = pathIt.current(); + seg = ++pathIt; + KoPoint extPoint; + bool ext = false; + float fsx = 0; + float yoffset = ( m_position == Above ? 0 : ( m_position == On ? m_font.pointSize() / 3 : m_font.pointSize() / 1.5 ) ); + kdDebug(38000) << "Position: " << m_position << " -> " << yoffset << endl; + for( unsigned int i = 0; i < m_text.length(); i++ ) + { + VPath* composite = m_glyphs.at( i ); + if( ! composite ) + continue; + // Step 1: place (0, 0) to the rotation center of the glyph. + dx = *glyphXAdvance.at( i ) / 2; + x += dx; + VTransformCmd trafo( 0L, QWMatrix( 1, 0, 0, 1, -dx, y + yoffset ) ); + trafo.visit( *composite ); + + // Step 2: find the position where to draw. + // 3 possibilities: before, on, and after the basePath... + if ( x < 0 ) + { + if( !ext ) + seg->pointTangentNormalAt( 0, &extPoint, &tangent, &normal ); + point = extPoint + x * tangent; + ext = true; + } + else + { + while ( seg && x > fsx + seg->length() ) + { + fsx += seg->length(); + oldSeg = seg; + seg = ++pathIt; + } + if( seg ) + { + ext = false; + sp = ( x - fsx ) / seg->length(); + seg->pointTangentNormalAt( sp, &point, &tangent, &normal ); + } + else + { + if( !ext ) + oldSeg->pointTangentNormalAt( 1, &extPoint, &tangent, &normal ); + point = extPoint + ( x - fsx ) * tangent; + ext = true; + } + } + + // Step 3: transform glyph and append it. That's it, we've got + // text following a path. Really easy, isn't it ;) ? + trafo.setMatrix( QWMatrix( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ) ); + trafo.visit( *composite ); + composite->setState( state() ); + + //kdDebug(38000) << "Glyph: " << (QString)character << " [String pos: " << x << ", " << y << " / Canvas pos: " << point.x() << ", " << point.y() << "]" << endl; + + x += dx; + y += *glyphYAdvance.at( i ); + } + FT_Done_Face( fontFace ); + FT_Done_FreeType( library ); + m_boundingBoxIsInvalid = true; +} + +// This routine is copied from KSVGFont (Rob) +QString +VText::buildRequest( QString family, int weight, int slant, double size, int &id ) +{ + // Strip those stupid [Xft or whatever]... + int pos; + if( ( pos = family.find( '[' ) ) ) + family = family.left( pos ); + + // Use FontConfig to locate & select fonts and use FreeType2 to open them + FcPattern *pattern; + QString fileName; + + pattern = FcPatternBuild( 0, FC_WEIGHT, FcTypeInteger, weight, + FC_SLANT, FcTypeInteger, slant, + FC_SIZE, FcTypeDouble, size, NULL ); + + // Add font name + FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>( family.latin1() ) ); + + // Disable hinting + FcPatternAddBool( pattern, FC_HINTING, FcFalse ); + // Enforce scalability + FcPatternAddBool( pattern, FC_SCALABLE, FcTrue ); + + // Perform the default font pattern modification operations. + FcDefaultSubstitute( pattern ); + FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern ); + + FcResult result; + + // we dont want to use bitmap fonts, so get a list of fonts sorted by closeness to pattern + // and use the best matching scalable font + FcFontSet *fset = FcFontSort( 0, pattern, FcFalse, 0L, &result ); + + // Destroy pattern + FcPatternDestroy( pattern ); + + if( fset ) + { + FcBool scalable; + FcChar8 *temp; + + // iterate over font list and take best scaleable font + for( int i = 0; i < fset->nfont; ++i ) + { + pattern = fset->fonts[i]; + if( FcResultMatch != FcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) ) + continue; + if( scalable == FcTrue ) + { + // Get index & filename + if( FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch || + FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch ) + { + kdDebug(38000) << "VText::buildRequest(), could not load font file for requested font \"" << family.latin1() << "\"" << endl; + return QString::null; + } + + fileName = QFile::decodeName(reinterpret_cast<const char *>( temp )); + + // get family name of matched font + QString newFamily; + + if( FcResultMatch == FcPatternGetString( pattern, FC_FAMILY, 0, &temp ) ) + m_font.setFamily( reinterpret_cast<const char *>( temp ) ); + + break; + } + } + + FcFontSetDestroy( fset ); + } + + + return fileName; +} + +void VText::setOffset( double offset ) +{ + if( offset < 0.0 ) + m_offset = 0.0; + else if( offset > 1.0 ) + m_offset = 1.0; + else + m_offset = offset; +} + +#endif // HAVE_KARBONTEXT diff --git a/karbon/core/vtext.h b/karbon/core/vtext.h new file mode 100644 index 00000000..962705ea --- /dev/null +++ b/karbon/core/vtext.h @@ -0,0 +1,136 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTEXT_H__ +#define __VTEXT_H__ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qptrlist.h> +#include <qstring.h> +#include <qfont.h> +#include <koffice_export.h> + +#include "vpath.h" +#include "vcomposite.h" + +class VGroup; + +typedef QPtrList<VPath> VPathList; +typedef QPtrListIterator<VPath> VPathListIterator; + +#ifdef Above +#undef Above +#endif + +class KARBONBASE_EXPORT VText : public VObject +{ +public: + enum Position { + Above, + On, + Under + }; + + enum Alignment { + Left, + Center, + Right + }; + + VText( VObject* parent, VState state = normal ); + VText( const QFont &font, const VSubpath& basePath, Position position, Alignment alignment, const QString& text ); + VText( const VText& text ); + virtual ~VText(); + virtual DCOPObject* dcopObject(); + + virtual void setText( const QString& text ); + virtual const QString& text() { return m_text; } + virtual void setFont( const QFont& font ) { m_font = font; } + virtual const QFont& font() { return m_font; } + virtual void setBasePath( const VSubpath& path ) { m_basePath = path; } + virtual VSubpath& basePath() { return m_basePath; } + virtual void setPosition( Position position ) { m_position = position; } + virtual Position position() { return m_position; } + virtual void setAlignment( Alignment alignment ) { m_alignment = alignment; } + virtual Alignment alignment() { return m_alignment; } + virtual void setUseShadow( bool state ) { m_shadow = state; } + virtual bool useShadow() { return m_shadow; } + virtual void setShadow( int angle, int distance, bool translucent ) + { m_translucentShadow = translucent; m_shadowAngle = angle; m_shadowDistance = distance; } + virtual bool translucentShadow() { return m_translucentShadow; } + virtual int shadowAngle() { return m_shadowAngle; } + virtual int shadowDistance() { return m_shadowDistance; } + virtual void setOffset( double offset ); + virtual double offset() { return m_offset; } + + /** + * Provides read only access to the glyphs. + */ + const VPathList& glyphs() const + { + return m_glyphs; + } + + virtual void draw( VPainter *painter, const KoRect* rect = 0L ) const; + + virtual const KoRect& boundingBox() const; + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + + virtual VText* clone() const; + virtual VGroup* toVGroup() const; + + virtual void setState( const VState state ); + + virtual void accept( VVisitor& visitor ); + +#ifdef HAVE_KARBONTEXT + void traceText(); + +protected: + QString buildRequest( QString family, int weight, int slant, double size, int &id ); +#endif // HAVE_KARBONTEXT + +private: + // The font to use to draw the text. + QFont m_font; + // The base path. Doesn't belong to the document. + VSubpath m_basePath; + // The text position + Position m_position; + // The text alignment + Alignment m_alignment; + // The text to draw + QString m_text; + // Shadow parameters + bool m_shadow; + bool m_translucentShadow; + int m_shadowDistance; + int m_shadowAngle; + // The glyphs (allow to keep a font even if not present on the computer. works as long as you don't edit the text.) + VPathList m_glyphs; + // the position offset + double m_offset; +}; + +#endif diff --git a/karbon/core/vtext_iface.cc b/karbon/core/vtext_iface.cc new file mode 100644 index 00000000..1a01b192 --- /dev/null +++ b/karbon/core/vtext_iface.cc @@ -0,0 +1,53 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vtext_iface.h" +#include "vtext.h" + +VTextIface::VTextIface( VText *text ) + : VObjectIface( text ), m_text( text ) +{ +} + +void +VTextIface::setText( QString text ) +{ + m_text->setText( text ); +} + +QString +VTextIface::text() +{ + return m_text->text(); +} + +void +VTextIface::setFontSize( int pointSize ) +{ + QFont font = m_text->font(); + font.setPointSize( pointSize ); + m_text->setFont( font ); +} + +int +VTextIface::fontSize() +{ + return m_text->font().pointSize(); +} + diff --git a/karbon/core/vtext_iface.h b/karbon/core/vtext_iface.h new file mode 100644 index 00000000..6cca452a --- /dev/null +++ b/karbon/core/vtext_iface.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTEXT_IFACE_H__ +#define __VTEXT_IFACE_H__ + +#include "vobject_iface.h" + +class VText; + +class VTextIface : public VObjectIface +{ + K_DCOP + +public: + VTextIface( VText *text ); + +k_dcop: + void setText( QString text ); + QString text(); + + void setFontSize( int pointSize ); + int fontSize(); + +private: + VText *m_text; +}; + +#endif + diff --git a/karbon/core/vvisitor.cc b/karbon/core/vvisitor.cc new file mode 100644 index 00000000..90085c4a --- /dev/null +++ b/karbon/core/vvisitor.cc @@ -0,0 +1,114 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vcomposite.h" +#include "vdocument.h" +#include "vgroup.h" +#include "vlayer.h" +#include "vpath.h" +#include "vselection.h" +#include "vvisitor.h" +#include "vimage.h" + +bool +VVisitor::visit( VObject& object ) +{ + m_success = false; + + object.accept( *this ); + + return m_success; +} + +void +VVisitor::visitVDocument( VDocument& document ) +{ + VLayerListIterator itr( document.layers() ); + + for( ; itr.current(); ++itr ) + { + itr.current()->accept( *this ); + } +} + +void +VVisitor::visitVGroup( VGroup& group ) +{ + VObjectListIterator itr( group.objects() ); + + for( ; itr.current(); ++itr ) + { + itr.current()->accept( *this ); + } +} + +void +VVisitor::visitVLayer( VLayer& layer ) +{ + VObjectListIterator itr( layer.objects() ); + + for( ; itr.current(); ++itr ) + { + itr.current()->accept( *this ); + } +} + +void +VVisitor::visitVPath( VPath& composite ) +{ + VSubpathListIterator itr( composite.paths() ); + + for( ; itr.current(); ++itr ) + { + if( !itr.current()->isEmpty() ) + itr.current()->accept( *this ); + } +} + +void +VVisitor::visitVSubpath( VSubpath& /*path*/ ) +{ +} + +void +VVisitor::visitVSelection( VSelection& selection ) +{ + VObjectListIterator itr( selection.objects() ); + + for( ; itr.current() ; ++itr ) + { + itr.current()->accept( *this ); + } +} + +void +VVisitor::visitVText( VText& /*text*/ ) +{ +} + +void +VVisitor::visitVImage( VImage& /*img*/ ) +{ +} + +void +VVisitor::visitVObject( VObject& /*object*/ ) +{ +} diff --git a/karbon/core/vvisitor.h b/karbon/core/vvisitor.h new file mode 100644 index 00000000..d442b9ca --- /dev/null +++ b/karbon/core/vvisitor.h @@ -0,0 +1,152 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VVISITOR_H__ +#define __VVISITOR_H__ + +#include <koffice_export.h> + +class VPath; +class VDocument; +class VGroup; +class VLayer; +class VObject; +class VSubpath; +class VSelection; +class VText; +class VImage; + +/** + \brief The abstract visitor class + + (From Wikipedia) + + In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. + + The idea is to use a structure of element classes, each of which has an accept method that takes a visitor object as an argument. The visitor is an interface that has a different visit() method for each element class. The accept() method of an element class calls back the visit() method for its class. Separate concrete visitor classes can then be written that perform some particular operations. + + One of these visit() methods of a concrete visitor can be thought of as methods not of a single class, but rather methods of a pair of classes: the concrete visitor and the particular element class. Thus the visitor pattern simulates double dispatch in a conventional single-dispatch object-oriented language such as Java, Smalltalk, and C++. + + The visitor pattern also specifies how iteration occurs over the object structure. In the simplest version, where each algorithm needs to iterate in the same way, the accept() method of a container element, in addition to calling back the visit() method of the visitor, also passes the visitor object to the accept() method of all its constituent child elements. + + Because the Visitor object has one principal function (manifested in a plurality of specialized methods) and that function is called visit(), the Visitor can be readily identified as a potential function object or functor. Likewise, the accept() function can be identified as a function applicator, a mapper, which knows how to traverse a particular type of object and apply a function to its elements. +*/ +class KARBONBASE_EXPORT VVisitor +{ +public: + /** + Constructs a new visitor class + */ + VVisitor() + { + m_success = false; + } + + /** + General visit method. Pass an \a object to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + Return the success value. + */ + virtual bool visit( VObject& object ); + + /** + Visit method for a VObject. Pass an \a object to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVObject( VObject& object ); + + /** + Visit method for a VPath. Pass a \a composite path to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVPath( VPath& composite ); + + /** + Visit method for a VDocument. Pass a \a document to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVDocument( VDocument& document ); + + /** + Visit method for a VGroup. Pass a \a group of objects to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVGroup( VGroup& group ); + + /** + Visit method for a VLayer. Pass a \a layer to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVLayer( VLayer& layer ); + + /** + Visit method for a VSubpath. Pass a \a path to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVSubpath( VSubpath& path ); + + /** + Visit method for a VSelection. Pass a \a selection to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVSelection( VSelection& selection ); + + /** + Visit method for a VText. Pass some \a text to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVText( VText& text ); + + /** + Visit method for a VImage. Pass an \a image to this function. + This is a virtual function so you need to implement it in the subclass if you want to use it. + */ + virtual void visitVImage( VImage& img ); + + /** + Return if the operation was a success or not + */ + bool success() const + { + return m_success; + } + +protected: + /* + * Make this class "abstract". + */ + /** + Destructs a visitor class + */ + virtual ~VVisitor() {} + + /** + Set the success property. + */ + void setSuccess( bool success = true ) + { + m_success = success; + } + +private: + bool m_success; +}; + +#endif + diff --git a/karbon/data/Makefile.am b/karbon/data/Makefile.am new file mode 100644 index 00000000..4ca75b2d --- /dev/null +++ b/karbon/data/Makefile.am @@ -0,0 +1,9 @@ +predefgradients_DATA = simple.kgr allcolors.kgr +predefgradientsdir = $(kde_datadir)/karbon/gradients + +xdg_apps_DATA = karbon.desktop + +rc_DATA = karbon.rc karbon_readonly.rc +rcdir = $(kde_datadir)/karbon +kde_services_DATA = karbonpart.desktop +kde_servicetypes_DATA = karbon_module.desktop diff --git a/karbon/data/allcolors.kgr b/karbon/data/allcolors.kgr new file mode 100644 index 00000000..eb6bdeef --- /dev/null +++ b/karbon/data/allcolors.kgr @@ -0,0 +1,25 @@ +<PREDEFGRADIENT> + <GRADIENT originX="0" originY="0" repeatMethod="2" type="0" vectorX="0" vectorY="50" > + <COLORSTOP ramppoint="0" midpoint="0.5" > + <COLOR v2="0" v3="0" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + <COLORSTOP ramppoint="0.183575" midpoint="0.5" > + <COLOR v2="0.882353" v3="0" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + <COLORSTOP ramppoint="0.347826" midpoint="0.5" > + <COLOR v2="1" v3="0" opacity="1" colorSpace="0" v1="0" /> + </COLORSTOP> + <COLORSTOP ramppoint="0.516908" midpoint="0.5" > + <COLOR v2="1" v3="1" opacity="1" colorSpace="0" v1="0" /> + </COLORSTOP> + <COLORSTOP ramppoint="0.68599" midpoint="0.5" > + <COLOR v2="0" v3="1" opacity="1" colorSpace="0" v1="0" /> + </COLORSTOP> + <COLORSTOP ramppoint="0.845411" midpoint="0.5" > + <COLOR v2="0" v3="0.984314" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + <COLORSTOP ramppoint="1" midpoint="0.5" > + <COLOR v2="0" v3="0.0156863" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + </GRADIENT> +</PREDEFGRADIENT> diff --git a/karbon/data/karbon.desktop b/karbon/data/karbon.desktop new file mode 100644 index 00000000..e484df4d --- /dev/null +++ b/karbon/data/karbon.desktop @@ -0,0 +1,70 @@ +[Desktop Entry] +Name=Karbon14 +Name[hi]=कार्बन 14 +Name[lo]=ຄາຣ໌ບອບ14 +Name[ne]=कार्बन१४ +Name[th]=คาร์บอน14 +Exec=karbon %u +GenericName=Scalable Graphics +GenericName[af]=Skaal veranderbare Grafieka +GenericName[ar]=رسوم قابلة للتمدُّد +GenericName[az]=Miqyaslı Qrafikalar +GenericName[bg]=Векторна графика +GenericName[ca]=Gràfics escalables +GenericName[cs]=Škálovatelná grafika +GenericName[cy]=Graffeg Graddadwy +GenericName[da]=Skalérbar grafik +GenericName[de]=Vektorgraphik +GenericName[el]=Διανυσματικά γραφικά +GenericName[eo]=Skaleblaj vektorgrafikoj +GenericName[es]=Gráficos escalables +GenericName[et]=Vektorgraafika +GenericName[eu]=Grafiko eskalagarriak +GenericName[fi]=Skaalattava grafiikka +GenericName[fr]=Graphiques vectoriels +GenericName[fy]=Fektorôfbyldings +GenericName[gl]=Imaxes Escalábeis +GenericName[he]=גרפיקה מדורגת +GenericName[hi]=स्केलेबल ग्राफिक्स +GenericName[hr]=Grafika u razmjeri +GenericName[hu]=Vektoros rajzoló +GenericName[it]=Grafica vettoriale +GenericName[ja]=スケーラブルグラフィックス +GenericName[km]=ក្រាហ្វិកអាចធ្វើមាត្រដ្ឋានបាន +GenericName[lo]=ຮູບເວກເຕີປັບຂະໝາດໄດ้ +GenericName[lt]=Kintamo dydžio grafika +GenericName[lv]=Mērogojama Grafika +GenericName[ms]=Grafik Boleh-skala +GenericName[mt]=Grafika tiddaqqas +GenericName[nb]=Skalerbart bilde +GenericName[nds]=Vektorgrafik +GenericName[ne]=मापनयोग्य ग्राफिक्स +GenericName[nl]=Vectorafbeeldingen +GenericName[nn]=Skalerbar grafikk +GenericName[pl]=Skalowalna grafika +GenericName[pt]=Imagens Escaláveis +GenericName[pt_BR]=Desenho +GenericName[ro]=Grafică scalabilă +GenericName[ru]=Векторные рисунки +GenericName[se]=Skálehahtti grafihkka +GenericName[sk]=Škálovateľná grafika +GenericName[sl]=Raztegljiva grafika +GenericName[sr]=Скалабилна графика +GenericName[sr@Latn]=Skalabilna grafika +GenericName[sv]=Skalbar grafik +GenericName[tg]=Сиёҳқаламии Пулакчадор +GenericName[th]=ภาพเวกเตอร์ปรับขนาดได้ +GenericName[tr]=Oranlanabilir Grafikler +GenericName[uk]=Масштабовна графіка +GenericName[uz]=Vektor grafikasi +GenericName[uz@cyrillic]=Вектор графикаси +GenericName[xh]=Imizobo Ekalishekayo +GenericName[zh_CN]=可缩放图像 +GenericName[zh_TW]=可縮放向量圖 +MimeType=application/vnd.oasis.opendocument.graphics;application/x-karbon;application/illustrator;image/x-eps;application/postscript +# kghostview has 6 for application/postscript, we need to be under that... +InitialPreference=5 +Type=Application +Icon=karbon +X-KDE-NativeMimeType=application/x-karbon +Categories=Qt;KDE;Office;X-KDE-More; diff --git a/karbon/data/karbon.rc b/karbon/data/karbon.rc new file mode 100644 index 00000000..ada9e11c --- /dev/null +++ b/karbon/data/karbon.rc @@ -0,0 +1,157 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd" > +<kpartgui name="Karbon" version="6"> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="file_import"/> + </Menu> + <Menu name="edit"> + <text>&Edit</text> + <Action name="koffice_undo"/> + <Action name="koffice_redo"/> + <Separator/> + <Action name="edit_cut"/> + <Action name="edit_copy"/> + <Action name="edit_paste"/> + <Action name="edit_select_all"/> + <Action name="edit_deselect_all"/> + <Action name="edit_delete"/> + <Separator/> + <Menu name="edit_purge"> + <text>P&urge</text> + <Action name="edit_purge_history"/> + </Menu> + </Menu> + <Menu name="view"> + <text>&View</text> + <Action name="view_newview"/> + <ActionList name="view_closeallviews"/> + <Separator/> + <ActionList name="view_split"/> + <Action name="view_zoom_in"/> + <Action name="view_zoom_out"/> + <Action name="view_zoom"/> + <Action name="view_mode"/> + <Separator/> + <Action name="view_palette_action_menu"/> + <Action name="view_tool_options"/> + <Action name="view_context_help"/> + <Separator/> + <Action name="view_show_margins"/> + <Action name="view_show_ruler"/> + <Action name="view_show_grid"/> + <Separator/> + <Action name="view_snap_to_grid"/> + </Menu> + <Menu name="object"> + <text>&Object</text> + <Action name="object_duplicate"/> + <Menu name="object_order"> + <text>&Order</text> + <Action name="object_move_totop"/> + <Action name="object_move_up"/> + <Action name="object_move_down"/> + <Action name="object_move_tobottom"/> + </Menu> + <Menu name="object_align"> + <text>&Align</text> + <Action name="object_align_horizontal_left"/> + <Action name="object_align_horizontal_center"/> + <Action name="object_align_horizontal_right"/> + <Separator/> + <Action name="object_align_vertical_top"/> + <Action name="object_align_vertical_center"/> + <Action name="object_align_vertical_bottom"/> + </Menu> + <Menu name="object_distribute"> + <text>&Distribute</text> + <Action name="object_distribute_horizontal_center"/> + <Action name="object_distribute_horizontal_gap"/> + <Action name="object_distribute_horizontal_left"/> + <Action name="object_distribute_horizontal_right"/> + <Separator/> + <Action name="object_distribute_vertical_center"/> + <Action name="object_distribute_vertical_gap"/> + <Action name="object_distribute_vertical_top"/> + <Action name="object_distribute_vertical_bottom"/> + </Menu> + <Action name="selection_group"/> + <Action name="selection_ungroup"/> + <Action name="close_path"/> + </Menu> + <Menu name="effects"> + <text>Effe&cts</text> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Separator group="settings_show"/> + <Action name="page_layout" group="settings_show"/> + <Separator group="settings_show"/> + <Action name="configure" group="settings_configure"/> + </Menu> + </MenuBar> + <ToolBar name="edit_toolbar" fullWidth="false"> + <Text>Edit</Text> + <Action name="koffice_undo"/> + <Action name="koffice_redo"/> + <Action name="edit_cut"/> + <Action name="edit_copy"/> + <Action name="edit_paste"/> + <Action name="edit_delete"/> + </ToolBar> + <ToolBar name="view_toolbar" fullWidth="false"> + <Text>View</Text> + <Action name="view_mode"/> + <Action name="view_zoom"/> + <Action name="help_context"/> + </ToolBar> + <ToolBar name="object_toolbar" fullWidth="false"> + <Text>Object</Text> + <Action name="setLineStyle"/> + <Action name="setLineWidth"/> + <Action name="object_move_totop"/> + <Action name="object_move_up"/> + <Action name="object_move_down"/> + <Action name="object_move_tobottom"/> + <Action name="selection_group"/> + <Action name="selection_ungroup"/> + </ToolBar> + <ToolBar name="Tools" position="left"> + <Text>Toolbox</Text> + </ToolBar> + <ToolBar name="align_toolbar" hidden="true" fullWidth="false"> + <Text>Align</Text> + <Action name="object_align_horizontal_left"/> + <Action name="object_align_horizontal_center"/> + <Action name="object_align_horizontal_right"/> + <Action name="object_align_vertical_top"/> + <Action name="object_align_vertical_center"/> + <Action name="object_align_vertical_bottom"/> + </ToolBar> + <ToolBar name="Effects" hidden="true" fullWidth="false"> + <Text>Effects</Text> + </ToolBar> + <Menu name="selection_popup"> + <Action name="edit_cut"/> + <Action name="edit_copy"/> + <Action name="edit_paste"/> + <Action name="edit_delete"/> + <Separator/> + <ActionList name="selection_type_action"/> + <Menu name="object_order"> + <text>&Order</text> + <Action name="object_move_totop"/> + <Action name="object_move_up"/> + <Action name="object_move_down"/> + <Action name="object_move_tobottom"/> + </Menu> + <Menu name="object_align"> + <text>&Align</text> + <Action name="object_align_horizontal_left"/> + <Action name="object_align_horizontal_center"/> + <Action name="object_align_horizontal_right"/> + <Separator/> + <Action name="object_align_vertical_top"/> + <Action name="object_align_vertical_center"/> + <Action name="object_align_vertical_bottom"/> + </Menu> + </Menu> +</kpartgui> diff --git a/karbon/data/karbon_module.desktop b/karbon/data/karbon_module.desktop new file mode 100644 index 00000000..cf6f7a15 --- /dev/null +++ b/karbon/data/karbon_module.desktop @@ -0,0 +1,41 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Karbon/CoreModule +Comment=Core functionality module for Karbon +Comment[bg]=Модул с основната функционалност на Karbon +Comment[ca]=Mòdul principal de funcionalitat per a Karbon +Comment[cy]=Modiwl swyddogaeth craidd ar gyfer Karbon +Comment[da]=Kernefunktionalitetsmodul for Karbon +Comment[de]=Kernmodul für Karbon +Comment[el]=Άρθρωμα βασικών λειτουργιών για το Karbon +Comment[eo]=Kernfunkcia modulo por Karbon +Comment[es]=Módulo de funcionalidad principal para Karbon +Comment[et]=Karboni tuumikfunktsioonide moodul +Comment[fa]=پیمانۀ کارآمدی هسته برای Karbon +Comment[fi]=Karbonin perustoiminnallisuusmoduuli +Comment[fr]=Module de fonctionnalités centrales de Karbon +Comment[fy]=Kernfunksjonaliteitsmodule foar Karbon +Comment[gl]=Módulo de funcionalidade de base para Karbon +Comment[he]=ליבת המודולים של Karbon +Comment[hu]=Karbon alapmodul +Comment[is]=Grunnvirkni eining fyrir Karbon +Comment[it]=Modulo di funzionalità fondamentale per Karbon +Comment[ja]=Karbon の中核的な機能モジュール +Comment[km]=ម៉ូឌុលមុខងារស្នូលសម្រាប់ Karbon +Comment[lv]=Pamatfunkcionalitātes modulis priekš Karbon +Comment[nb]=Karbon-modul for kjernefunksjonalitet +Comment[nds]=Karnmoduul för Karbon +Comment[ne]=कार्बनका लागि कोर कार्यात्मक मोड्युल +Comment[nl]=Kernfunctionaliteitmodule voor Karbon +Comment[pl]=Moduł podstawowej funkcjonalności dla Karbon +Comment[pt]=Módulo de funcionalidade de base para o Karbon +Comment[pt_BR]=Módulo de funcionalidade básica para o Karbon +Comment[ru]=Базовый модуль Karbon +Comment[sk]=Základný funkčný modul pre Karbon +Comment[sl]=Modul za osnovne zmožnosti Karbona +Comment[sr]=Модул основне функционалности за Karbon +Comment[sr@Latn]=Modul osnovne funkcionalnosti za Karbon +Comment[sv]=Modul med kärnfunktioner för Karbon +Comment[uk]=Модуль базової функціональності Karbon +Comment[zh_CN]=Karbon 的核心功能模块 +Comment[zh_TW]=Karbon 的核心功能模組 diff --git a/karbon/data/karbon_readonly.rc b/karbon/data/karbon_readonly.rc new file mode 100644 index 00000000..54ea85c1 --- /dev/null +++ b/karbon/data/karbon_readonly.rc @@ -0,0 +1,24 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd" > +<kpartgui name="Karbon" version="2"> +<MenuBar> + <Menu name="edit"> + <text>&Edit</text> + <Action name="edit_copy"/> + <Action name="edit_select_all"/> + <Action name="edit_deselect_all"/> + </Menu> + <Menu name="view"> + <text>&View</text> + <Action name="view_zoom_in"/> + <Action name="view_zoom_out"/> + <Action name="view_zoom"/> + <Action name="view_mode"/> + </Menu> +</MenuBar> +<ToolBar name="view_toolbar" fullWidth="false"> + <Text>View</Text> + <Separator/> + <Action name="view_mode"/> + <Action name="view_zoom"/> +</ToolBar> +</kpartgui> diff --git a/karbon/data/karbonpart.desktop b/karbon/data/karbonpart.desktop new file mode 100644 index 00000000..6f09da4a --- /dev/null +++ b/karbon/data/karbonpart.desktop @@ -0,0 +1,115 @@ +[Desktop Entry] +Name=KOffice Scalable Graphics Component +Name[bg]=Компонент за векторна графика в KOffice +Name[ca]=Component de gràfics escalables de KOffice +Name[cs]=SVG komponenta pro KOffice +Name[cy]=Cydran Graffeg Graddadwy KOffice +Name[da]=Koffice skalérbar grafikkomponent +Name[de]=KOffice-Komponente für Vektorgraphiken +Name[el]=Συστατικό διανυσματικών γραφικών του KOffice +Name[eo]=Komponanto por skalebla grafiko +Name[es]=Componente de gráfico escalable de KOffice +Name[et]=KOffice'i vektorgraafika komponent +Name[eu]=KOffice-en grafiko eskalagarrien osagaia +Name[fi]=KOfficen vektorigrafiikkakomponentti +Name[fr]=Composant graphiques vectoriels de KOffice +Name[fy]=KOffice fektorôfbyldings komponint +Name[gl]=Componente de Imaxes Escalábeis de KOffice +Name[he]=רכיב גרפיקה מדורגת של KOffice +Name[hi]=के-ऑफ़िस स्केलेबल ग्राफिक्स अवयव +Name[hu]=KOffice vektoros rajzolókomponens +Name[is]=KOffice Scalable Graphics hluti +Name[it]=Componente per grafica vettoriale di KOffice +Name[ja]=KOffice スケーラブルグラフィックス コンポーネント +Name[km]=សមាសភាគក្រាហ្វិកអាចធ្វើមាត្រដ្ឋានបានសម្រាប់ KOffice +Name[lv]=KOffice mērogojamas grafikas komponente +Name[ms]=Komponen Grafik Boleh Skala KOffice +Name[nb]=Skalerbar bilde-komponent for KOffice +Name[nds]=KOffice-Komponent för Vektorgrafiken +Name[ne]=केडीई कार्यालय मापनयोग्य ग्राफिक्स अवयव +Name[nl]=Koffice Vectorafbeeldingen Component +Name[nn]=Skalerbar grafikkomponent for KOffice +Name[pl]=Komponent KOffice dla skalowalnej grafiki +Name[pt]=Componente de Imagens Escaláveis do KOffice +Name[pt_BR]=Componente de Imagens Vetoriais do KOffice +Name[ru]=Компонент векторных рисунков KOffice +Name[se]=KOffice:a skálehahtti grafihkkaoassi +Name[sk]=Komponent škálovateľnej grafiky KOffice +Name[sl]=Komponenta raztegljive grafike za KOffice +Name[sr]=KOffice-ова компонента скалабилне графика +Name[sr@Latn]=KOffice-ova komponenta skalabilne grafika +Name[sv]=Koffice skalbar grafikkomponent +Name[tg]=Сиёҳқаламии Пулакчадори компоненти KOffice +Name[tr]=KOffice Oranlanabilir Grafik Bileşeni +Name[uk]=Компонент векторної графіки KOffice +Name[uz]=KOffice vektor rasmlar komponenti +Name[uz@cyrillic]=KOffice вектор расмлар компоненти +Name[wa]=Componint grafikes schålåves di Koffice +Name[zh_CN]=KOffice 可缩放图像组件 +Name[zh_TW]=KOffice 可縮放圖片元件 +X-KDE-Library=libkarbonpart +MimeType=application/x-karbon;application/illustrator;image/x-eps;application/postscript;application/vnd.oasis.opendocument.graphics;application/vnd.oasis.opendocument.graphics-template +# kghostview has 6 for application/postscript, we need to be under that... +InitialPreference=5 +Type=Service +ServiceTypes=KOfficePart,KParts/ReadOnlyPart,KParts/ReadWritePart +X-KDE-NativeMimeType=application/x-karbon +X-KDE-NativeOasisMimeType=application/vnd.oasis.opendocument.graphics +X-KDE-ExtraNativeMimeTypes=application/vnd.oasis.opendocument.graphics,application/vnd.oasis.opendocument.graphics-template +GenericName=Scalable Graphics +GenericName[af]=Skaal veranderbare Grafieka +GenericName[ar]=رسوم قابلة للتمدُّد +GenericName[az]=Miqyaslı Qrafikalar +GenericName[bg]=Векторна графика +GenericName[ca]=Gràfics escalables +GenericName[cs]=Škálovatelná grafika +GenericName[cy]=Graffeg Graddadwy +GenericName[da]=Skalérbar grafik +GenericName[de]=Vektorgraphik +GenericName[el]=Διανυσματικά γραφικά +GenericName[eo]=Skaleblaj vektorgrafikoj +GenericName[es]=Gráficos escalables +GenericName[et]=Vektorgraafika +GenericName[eu]=Grafiko eskalagarriak +GenericName[fi]=Skaalattava grafiikka +GenericName[fr]=Graphiques vectoriels +GenericName[fy]=Fektorôfbyldings +GenericName[gl]=Imaxes Escalábeis +GenericName[he]=גרפיקה מדורגת +GenericName[hi]=स्केलेबल ग्राफिक्स +GenericName[hr]=Grafika u razmjeri +GenericName[hu]=Vektoros rajzoló +GenericName[it]=Grafica vettoriale +GenericName[ja]=スケーラブルグラフィックス +GenericName[km]=ក្រាហ្វិកអាចធ្វើមាត្រដ្ឋានបាន +GenericName[lo]=ຮູບເວກເຕີປັບຂະໝາດໄດ้ +GenericName[lt]=Kintamo dydžio grafika +GenericName[lv]=Mērogojama Grafika +GenericName[ms]=Grafik Boleh-skala +GenericName[mt]=Grafika tiddaqqas +GenericName[nb]=Skalerbart bilde +GenericName[nds]=Vektorgrafik +GenericName[ne]=मापनयोग्य ग्राफिक्स +GenericName[nl]=Vectorafbeeldingen +GenericName[nn]=Skalerbar grafikk +GenericName[pl]=Skalowalna grafika +GenericName[pt]=Imagens Escaláveis +GenericName[pt_BR]=Desenho +GenericName[ro]=Grafică scalabilă +GenericName[ru]=Векторные рисунки +GenericName[se]=Skálehahtti grafihkka +GenericName[sk]=Škálovateľná grafika +GenericName[sl]=Raztegljiva grafika +GenericName[sr]=Скалабилна графика +GenericName[sr@Latn]=Skalabilna grafika +GenericName[sv]=Skalbar grafik +GenericName[tg]=Сиёҳқаламии Пулакчадор +GenericName[th]=ภาพเวกเตอร์ปรับขนาดได้ +GenericName[tr]=Oranlanabilir Grafikler +GenericName[uk]=Масштабовна графіка +GenericName[uz]=Vektor grafikasi +GenericName[uz@cyrillic]=Вектор графикаси +GenericName[xh]=Imizobo Ekalishekayo +GenericName[zh_CN]=可缩放图像 +GenericName[zh_TW]=可縮放向量圖 +Icon=karbon diff --git a/karbon/data/simple.kgr b/karbon/data/simple.kgr new file mode 100644 index 00000000..568755ee --- /dev/null +++ b/karbon/data/simple.kgr @@ -0,0 +1,11 @@ +<!DOCTYPE PREDEFGRADIENT> +<PREDEFGRADIENT> + <GRADIENT originX="0" originY="0" repeatMethod="1" type="0" vectorX="0" vectorY="50" > + <COLORSTOP ramppoint="0" midpoint="0.5" > + <COLOR v2="0" v3="0" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + <COLORSTOP ramppoint="1" midpoint="0.5" > + <COLOR v2="1" v3="0" opacity="1" colorSpace="0" v1="1" /> + </COLORSTOP> + </GRADIENT> +</PREDEFGRADIENT> diff --git a/karbon/dialogs/Makefile.am b/karbon/dialogs/Makefile.am new file mode 100644 index 00000000..7856355a --- /dev/null +++ b/karbon/dialogs/Makefile.am @@ -0,0 +1,22 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../commands \ + $(all_includes) + +noinst_LTLIBRARIES = \ + libkarbondialogs.la + +noinst_HEADERS = \ + vcolordlg.h \ + vconfiguredlg.h \ + vcolortab.h + +libkarbondialogs_la_SOURCES = \ + vcolordlg.cc \ + vconfiguredlg.cc \ + vcolortab.cc + +libkarbondialogs_la_METASOURCES = \ + AUTO + diff --git a/karbon/dialogs/vcolordlg.cc b/karbon/dialogs/vcolordlg.cc new file mode 100644 index 00000000..6acefa24 --- /dev/null +++ b/karbon/dialogs/vcolordlg.cc @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <klocale.h> + +#include "vcolor.h" +#include "vcolordlg.h" +#include "vcolortab.h" + +VColorDlg::VColorDlg( const VColor &c, QWidget* parent, const char* name ) + : KDialogBase ( parent, name, true, i18n( "Uniform Color" ), + KDialogBase::Ok | KDialogBase::Cancel ) +{ + m_colortab = new VColorTab( VColor( c ), this, name ); + + setMainWidget( m_colortab ); + setFixedSize( baseSize() ); +} + +VColor +VColorDlg::Color() +{ + return m_colortab->Color(); +} + + +#include "vcolordlg.moc" + diff --git a/karbon/dialogs/vcolordlg.h b/karbon/dialogs/vcolordlg.h new file mode 100644 index 00000000..820bb1bf --- /dev/null +++ b/karbon/dialogs/vcolordlg.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOLORDLG_H__ +#define __VCOLORDLG_H__ + +#include <kdialogbase.h> + +class VColor; +class VColorTab; +class VFill; + +class VColorDlg : public KDialogBase +{ + Q_OBJECT + +public: + VColorDlg( const VColor &c, QWidget* parent = 0L, const char* name = 0L ); + + VColor Color(); + +private: + VColorTab* m_colortab; +}; +#endif + diff --git a/karbon/dialogs/vcolortab.cc b/karbon/dialogs/vcolortab.cc new file mode 100644 index 00000000..037fdc6e --- /dev/null +++ b/karbon/dialogs/vcolortab.cc @@ -0,0 +1,199 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> + +#include <kcolordialog.h> +#include <klocale.h> +#include <knuminput.h> + +#include "vcolor.h" +#include "vfillcmd.h" +#include "vcolortab.h" +#include "vselection.h" + +#include <kdebug.h> + + +VColorTab::VColorTab( const VColor &c, QWidget* parent, const char* name ) + : QTabWidget( parent, name ) +{ + QGridLayout *mainLayout; + + mRGBWidget = new QWidget( this ); + mainLayout = new QGridLayout( mRGBWidget, 3, 3 ); + mColorSelector = new KHSSelector( mRGBWidget ); + mColorSelector->setMinimumHeight( 165 ); + mColorSelector->setMinimumWidth( 165 ); + connect( mColorSelector, SIGNAL( valueChanged( int, int ) ), this, SLOT( slotHSChanged( int, int ) ) ); + mainLayout->addMultiCellWidget(mColorSelector, 0, 2, 0, 0 ); + + //Selector + mSelector = new KGradientSelector( KSelector::Vertical, mRGBWidget ); + mSelector->setColors( QColor( "white" ), QColor( "black" ) ); + mSelector->setMinimumWidth( 20 ); + //TODO: Make it autochange color if the solid-filled object is selected (also for QSpinBoxes) + connect( mSelector, SIGNAL( valueChanged( int ) ), this, SLOT( slotVChanged( int ) ) ); + mainLayout->addMultiCellWidget( mSelector, 0, 2, 1, 1 ); + + //Reference + QGroupBox* groupbox = new QGroupBox( 2, Vertical, i18n( "Reference" ), mRGBWidget ); + new QLabel( i18n( "Old:" ), groupbox ); + new QLabel( i18n( "New:" ), groupbox ); + mOldColor = new KColorPatch( groupbox ); + mColorPreview = new KColorPatch( groupbox ); + + QColor color( c ); + mOldColor->setColor( color ); + mColorPreview->setColor( color ); + mainLayout->addWidget( groupbox, 0, 2 ); + + //Components + QGroupBox* cgroupbox = new QGroupBox( 3, Vertical, i18n( "Components" ), mRGBWidget ); + + //--->RGB + new QLabel( i18n( "R:" ), cgroupbox ); + new QLabel( i18n( "G:" ), cgroupbox ); + new QLabel( i18n( "B:" ), cgroupbox ); + mRed = new KIntSpinBox( 0, 255, 1, 0, 10, cgroupbox ); + mGreen = new KIntSpinBox( 0, 255, 1, 0, 10, cgroupbox ); + mBlue = new KIntSpinBox( 0, 255, 1, 0, 10, cgroupbox ); + connect( mRed, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromRGBSpinBoxes() ) ); + connect( mGreen, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromRGBSpinBoxes() ) ); + connect( mBlue, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromRGBSpinBoxes() ) ); + + //--->HSV + new QLabel( i18n( "Hue:", "H:" ), cgroupbox ); + new QLabel( i18n( "Saturation:", "S:" ), cgroupbox ); + new QLabel( i18n( "Value:", "V:" ), cgroupbox ); + mHue = new KIntSpinBox( 0, 359, 1, 0, 10, cgroupbox ); + mSaturation = new KIntSpinBox( 0, 255, 1, 0, 10, cgroupbox ); + mValue = new KIntSpinBox( 0, 255, 1, 0, 10, cgroupbox ); + connect( mHue, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromHSVSpinBoxes() ) ); + connect( mSaturation, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromHSVSpinBoxes() ) ); + connect( mValue, SIGNAL( valueChanged(int) ), this, SLOT( slotUpdateFromHSVSpinBoxes() ) ); + mainLayout->addWidget( cgroupbox, 1, 2 ); + + //--->Opacity + QGroupBox* ogroupBox = new QGroupBox( 1, Vertical, i18n( "Opacity" ), mRGBWidget ); + mOpacity = new KIntNumInput( 100, ogroupBox ); + mOpacity->setRange( 0, 100, 1, true ); + mOpacity->setValue( int( c.opacity() * 100.0 ) ); + mainLayout->addWidget( ogroupBox, 2, 2 ); + + mainLayout->setSpacing( 2 ); + mainLayout->setMargin( 5 ); + + mainLayout->activate(); + + addTab( mRGBWidget, i18n( "RGB" ) ); + + mRed->setValue( color.red() ); + mGreen->setValue( color.green() ); + mBlue->setValue( color.blue() ); +} + +void VColorTab::slotUpdateFromRGBSpinBoxes() +{ + QColor color( mRed->value(), mGreen->value(), mBlue->value(), QColor::Rgb ); + mColorPreview->setColor( color ); + mColorPreview->update(); + + // set HSV + mHue->blockSignals( true ); + mSaturation->blockSignals( true ); + mValue->blockSignals( true ); + + int h, s, v; + color.hsv( &h, &s, &v ); + mHue->setValue( h ); + mSaturation->setValue( s ); + mValue->setValue( v ); + + // update gradient selector + mSelector->blockSignals( true ); + mColorSelector->setValues( h, s ); + slotHSChanged( h, s ); + mSelector->setValue( static_cast<int>( ( float( mValue->value() ) / 255.0 ) * 99.0 ) ); + mSelector->blockSignals( false ); + + mHue->blockSignals( false ); + mSaturation->blockSignals( false ); + mValue->blockSignals( false ); +} + +void VColorTab::slotUpdateFromHSVSpinBoxes() +{ + QColor color( mHue->value(), mSaturation->value(), mValue->value(), QColor::Hsv ); + mColorPreview->setColor( color ); + mColorPreview->update(); + + // update gradient selector + mSelector->blockSignals( true ); + mSelector->setValue( static_cast<int>( ( float( mValue->value() ) / 255.0 ) * 99.0 ) ); + mSelector->blockSignals( false ); + + // set RGB + mRed->blockSignals( true ); + mGreen->blockSignals( true ); + mBlue->blockSignals( true ); + + mRed->setValue( color.red() ); + mGreen->setValue( color.green() ); + mBlue->setValue( color.blue() ); + + mRed->blockSignals( false ); + mGreen->blockSignals( false ); + mBlue->blockSignals( false ); +} + +VColor VColorTab::Color() +{ + kdDebug() << "VColorTab::slotApplyButtonPressed" << endl; + float r = mRed->value() / 255.0, g = mGreen->value() / 255.0, b = mBlue->value() / 255.0; + float op = mOpacity->value() / 100.0; + + VColor c; + c.set( r, g, b ); + c.setOpacity( op ); + + return c; +} + +void VColorTab::slotHSChanged( int h, int s ) +{ + //QColor color( mHue->value(), mSaturation->value(), newVal, QColor::Hsv ); + mHue->setValue( h ); + mSaturation->setValue( s ); + QColor color1( h, s, 255, QColor::Hsv ); + QColor color2( h, s, 0, QColor::Hsv ); + mSelector->setColors( color1, color2 ); +} + +void VColorTab::slotVChanged( int newVal ) +{ + //QColor color( mHue->value(), mSaturation->value(), newVal, QColor::Hsv ); + mValue->setValue( static_cast<int>( float( newVal ) / 99.0 * 255.0 ) ); +} + +#include "vcolortab.moc" + diff --git a/karbon/dialogs/vcolortab.h b/karbon/dialogs/vcolortab.h new file mode 100644 index 00000000..18a00f7c --- /dev/null +++ b/karbon/dialogs/vcolortab.h @@ -0,0 +1,65 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOLORTAB_H +#define __VCOLORTAB_H + +#include <qtabwidget.h> + +class QColor; +class KHSSelector; +class KIntSpinBox; +class KGradientSelector; +class KColorPatch; +class KIntNumInput; +class VColor; + +class VColorTab : public QTabWidget +{ + Q_OBJECT + +public: + VColorTab( const VColor &c, QWidget* parent = 0L, const char* name = 0L ); + + VColor Color(); + +private: + QWidget* mRGBWidget; + KHSSelector* mColorSelector; + KIntSpinBox* mRed; + KIntSpinBox* mGreen; + KIntSpinBox* mBlue; + KIntSpinBox* mHue; + KIntSpinBox* mSaturation; + KIntSpinBox* mValue; + KIntNumInput* mOpacity; + KGradientSelector* mSelector; + KColorPatch* mOldColor; + KColorPatch* mColorPreview; + +private slots: + void slotUpdateFromRGBSpinBoxes(); + void slotUpdateFromHSVSpinBoxes(); + void slotVChanged( int ); + void slotHSChanged( int, int ); +}; + +#endif + diff --git a/karbon/dialogs/vconfiguredlg.cc b/karbon/dialogs/vconfiguredlg.cc new file mode 100644 index 00000000..c8439753 --- /dev/null +++ b/karbon/dialogs/vconfiguredlg.cc @@ -0,0 +1,461 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <float.h> + +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qvbox.h> +#include <qvgroupbox.h> +#include <qcombobox.h> +#include <qgrid.h> + +#include <kiconloader.h> +#include <kconfig.h> +#include <kdialogbase.h> +#include <klocale.h> +#include <knuminput.h> +#include <kcolorbutton.h> +#include <KoUnitWidgets.h> + +#include "karbon_view.h" +#include "karbon_part.h" +#include "karbon_factory.h" + +#include "vconfiguredlg.h" + + +VConfigureDlg::VConfigureDlg( KarbonView* parent ) + : KDialogBase( KDialogBase::IconList, i18n( "Configure" ), + KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel | KDialogBase::Default, + KDialogBase::Ok, parent ) + +{ + QVBox * page = addVBoxPage( + i18n( "Interface" ), i18n( "Interface" ), + BarIcon( "misc", KIcon::SizeMedium ) ); + + m_interfacePage = new VConfigInterfacePage( parent, page ); + + page = addVBoxPage( + i18n( "Misc" ), i18n( "Misc" ), + BarIcon( "misc", KIcon::SizeMedium ) ); + + m_miscPage = new VConfigMiscPage( parent, page ); + + page = addVBoxPage( + i18n( "Grid" ), i18n( "Grid" ), + BarIcon( "grid", KIcon::SizeMedium ) ); + + m_gridPage = new VConfigGridPage( parent, page ); + + connect( m_miscPage, SIGNAL( unitChanged( int ) ), m_gridPage, SLOT( slotUnitChanged( int ) ) ); + + page = addVBoxPage( + i18n( "Document" ), i18n( "Document Settings" ), + BarIcon( "document", KIcon::SizeMedium ) ); + + m_defaultDocPage = new VConfigDefaultPage( parent, page ); + connect( this, SIGNAL( okClicked() ), this, SLOT( slotApply() ) ); +} + +void VConfigureDlg::slotApply() +{ + m_interfacePage->apply(); + m_miscPage->apply(); + m_defaultDocPage->apply(); + m_gridPage->apply(); +} + +void VConfigureDlg::slotDefault() +{ + switch( activePageIndex() ) + { + case 0: m_interfacePage->slotDefault(); + break; + case 1: m_miscPage->slotDefault(); + break; + case 2: m_gridPage->slotDefault(); + break; + case 3: m_defaultDocPage->slotDefault(); + break; + default: + break; + } +} + + +VConfigInterfacePage::VConfigInterfacePage( KarbonView* view, + QVBox* box, char* name ) + : QObject( box->parent(), name ) +{ + m_view = view; + m_config = KarbonFactory::instance()->config(); + + m_oldRecentFiles = 10; + m_oldCopyOffset = 10; + m_oldDockerFontSize = 8; + bool oldShowStatusBar = true; + + QVGroupBox* tmpQGroupBox = new QVGroupBox( i18n( "Interface" ), box ); + + m_config->setGroup( "" ); + + m_oldDockerFontSize = m_config->readNumEntry( "palettefontsize", m_oldDockerFontSize ); + + if( m_config->hasGroup( "Interface" ) ) + { + m_config->setGroup( "Interface" ); + + m_oldRecentFiles = m_config->readNumEntry( + "NbRecentFile", m_oldRecentFiles ); + + oldShowStatusBar = m_config->readBoolEntry( + "ShowStatusBar" , true ); + + m_oldCopyOffset = m_config->readNumEntry( + "CopyOffset", m_oldCopyOffset ); + } + + m_showStatusBar = new QCheckBox( i18n( "Show status bar" ), tmpQGroupBox ); + m_showStatusBar->setChecked( oldShowStatusBar ); + + m_recentFiles = new KIntNumInput( m_oldRecentFiles, tmpQGroupBox ); + m_recentFiles->setRange( 1, 20, 1 ); + m_recentFiles->setLabel( i18n( "Number of recent files:" ) ); + + m_copyOffset = new KIntNumInput( m_oldCopyOffset, tmpQGroupBox ); + m_copyOffset->setRange( 1, 50, 1 ); + m_copyOffset->setLabel( i18n( "Copy offset:" ) ); + + m_dockerFontSize = new KIntNumInput( m_oldDockerFontSize, tmpQGroupBox ); + m_dockerFontSize->setRange( 5, 20, 1 ); + m_dockerFontSize->setLabel( i18n( "Palette font size:" ) ); +} + +void VConfigInterfacePage::apply() +{ + bool showStatusBar = m_showStatusBar->isChecked(); + + KarbonPart* part = m_view->part(); + + m_config->setGroup( "Interface" ); + + int recent = m_recentFiles->value(); + + if( recent != m_oldRecentFiles ) + { + m_config->writeEntry( "NbRecentFile", recent ); + m_view->setNumberOfRecentFiles( recent ); + m_oldRecentFiles = recent; + } + + int copyOffset = m_copyOffset->value(); + + if( copyOffset != m_oldCopyOffset ) + { + m_config->writeEntry( "CopyOffset", copyOffset ); + m_oldCopyOffset = copyOffset; + } + + bool refreshGUI = false; + + if( showStatusBar != part->showStatusBar() ) + { + m_config->writeEntry( "ShowStatusBar", showStatusBar ); + part->setShowStatusBar( showStatusBar ); + refreshGUI = true; + } + + m_config->setGroup( "" ); + + int dockerFontSize = m_dockerFontSize->value(); + + if( dockerFontSize != m_oldDockerFontSize ) + { + m_config->writeEntry( "palettefontsize", dockerFontSize ); + m_oldDockerFontSize = dockerFontSize; + refreshGUI = true; + } + + if( refreshGUI ) + part->reorganizeGUI(); + +} + +void VConfigInterfacePage::slotDefault() +{ + m_recentFiles->setValue( 10 ); + m_dockerFontSize->setValue( 8 ); + m_showStatusBar->setChecked( true ); +} + + +VConfigMiscPage::VConfigMiscPage( KarbonView* view, QVBox* box, char* name ) + : QObject( box->parent(), name ) +{ + m_view = view; + m_config = KarbonFactory::instance()->config(); + + KoUnit::Unit unit = view->part()->unit(); + + QGroupBox* tmpQGroupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Misc" ), box, "GroupBox" ); + tmpQGroupBox->layout()->setSpacing(KDialog::spacingHint()); + tmpQGroupBox->layout()->setMargin(KDialog::marginHint()); + + QGridLayout* grid = new QGridLayout(tmpQGroupBox->layout(), 4, 2 ); + + m_oldUndoRedo = 30; + + QString unitType = KoUnit::unitName( unit ); + //#################"laurent + //don't load unitType from config file because unit is + //depend from kword file => unit can be different from config file + + if( m_config->hasGroup( "Misc" ) ) + { + m_config->setGroup( "Misc" ); + m_oldUndoRedo = m_config->readNumEntry( "UndoRedo", m_oldUndoRedo ); + } + + m_undoRedo = new KIntNumInput( m_oldUndoRedo, tmpQGroupBox ); + m_undoRedo->setLabel( i18n( "Undo/redo limit:" ) ); + m_undoRedo->setRange( 10, 60, 1 ); + + grid->addMultiCellWidget( m_undoRedo, 0, 0, 0, 1 ); + + grid->addWidget( new QLabel( i18n( "Units:" ), tmpQGroupBox ), 1, 0 ); + + m_unit = new QComboBox( tmpQGroupBox ); + m_unit->insertStringList( KoUnit::listOfUnitName() ); + grid->addWidget( m_unit, 1, 1 ); + m_oldUnit = KoUnit::unit( unitType ); + m_unit->setCurrentItem( m_oldUnit ); + connect( m_unit, SIGNAL( activated( int ) ), SIGNAL( unitChanged( int ) ) ); +} + +void VConfigMiscPage::apply() +{ + KarbonPart * part = m_view->part(); + + m_config->setGroup( "Misc" ); + + if( m_oldUnit != m_unit->currentItem() ) + { + m_oldUnit = m_unit->currentItem(); + part->setUnit( static_cast<KoUnit::Unit>( m_oldUnit ) ); + part->document().setUnit(part->unit()); + m_config->writeEntry( "Units", KoUnit::unitName( part->unit() ) ); + } + + int newUndo = m_undoRedo->value(); + + if( newUndo != m_oldUndoRedo ) + { + m_config->writeEntry( "UndoRedo", newUndo ); + part->setUndoRedoLimit( newUndo ); + m_oldUndoRedo = newUndo; + } +} + +void VConfigMiscPage::slotDefault() +{ + m_undoRedo->setValue( 30 ); + m_unit->setCurrentItem( 0 ); +} + +VConfigGridPage::VConfigGridPage( KarbonView* view, QVBox* page, char* name ) + : QObject( page->parent(), name ) +{ + m_view = view; + KoUnit::Unit unit = view->part()->document().unit(); + KarbonGridData &gd = view->part()->document().grid(); + double pgw = view->part()->document().width(); + double pgh = view->part()->document().height(); + double fw = gd.freq.width(); + double fh = gd.freq.height(); + double sw = gd.snap.width(); + double sh = gd.snap.height(); + + m_gridChBox = new QCheckBox( i18n( "Show &grid" ), page ); + m_gridChBox->setChecked( gd.isShow ); + m_snapChBox = new QCheckBox( i18n( "Snap to g&rid" ), page ); + m_snapChBox->setChecked( gd.isSnap ); + QLabel* gridColorLbl = new QLabel( i18n( "Grid &color:" ), page); + m_gridColorBtn = new KColorButton( gd.color, page ); + gridColorLbl->setBuddy( m_gridColorBtn ); + QGroupBox* spacingGrp = new QGroupBox( 2, Qt::Horizontal, i18n( "Spacing" ), page ); + QLabel* spaceHorizLbl = new QLabel( i18n( "&Horizontal:" ), spacingGrp ); + m_spaceHorizUSpin = new KoUnitDoubleSpinBox( spacingGrp, 0.0, pgw, 0.1, fw, unit ); + spaceHorizLbl->setBuddy( m_spaceHorizUSpin ); + QLabel* spaceVertLbl = new QLabel( i18n( "&Vertical:" ), spacingGrp ); + m_spaceVertUSpin = new KoUnitDoubleSpinBox( spacingGrp, 0.0, pgh, 0.1, fh, unit ); + spaceVertLbl->setBuddy( m_spaceVertUSpin ); + QGroupBox* snapGrp = new QGroupBox( 2, Qt::Horizontal, i18n( "Snap Distance" ), page ); + QLabel* snapHorizLbl = new QLabel( i18n( "H&orizontal:" ), snapGrp ); + m_snapHorizUSpin = new KoUnitDoubleSpinBox( snapGrp, 0.0, fw, 0.1, sw, unit ); + snapHorizLbl->setBuddy( m_snapHorizUSpin ); + QLabel* snapVertLbl = new QLabel( i18n( "V&ertical:" ), snapGrp ); + m_snapVertUSpin = new KoUnitDoubleSpinBox( snapGrp, 0.0, fh, 0.1, sh, unit ); + snapVertLbl->setBuddy( m_snapVertUSpin ); + + QGridLayout* gl = new QGridLayout(); + gl->setSpacing( KDialog::spacingHint() ); + gl->addMultiCellWidget( m_gridChBox, 0, 0, 0, 2 ); + gl->addMultiCellWidget( m_snapChBox, 1, 1, 0, 2 ); + gl->addWidget( gridColorLbl, 2, 0) ; + gl->addWidget( m_gridColorBtn, 2, 1 ); + gl->addItem( new QSpacerItem( 0, 0 ), 2, 2 ); + gl->addMultiCellWidget( spacingGrp, 3, 3, 0, 2 ); + gl->addMultiCellWidget( snapGrp, 4, 4, 0, 2 ); + gl->addMultiCell( new QSpacerItem( 0, 0 ), 5, 5, 0, 2 ); + + connect( m_spaceHorizUSpin, SIGNAL( valueChanged( double ) ), SLOT( setMaxHorizSnap( double ) ) ); + connect( m_spaceVertUSpin, SIGNAL( valueChanged( double ) ), SLOT( setMaxVertSnap( double ) ) ) ; +} + +void VConfigGridPage::setMaxHorizSnap( double v ) +{ + m_snapHorizUSpin->setMaxValue( v ); +} + +void VConfigGridPage::setMaxVertSnap( double v ) +{ + m_snapVertUSpin->setMaxValue( v ); +} + +void VConfigGridPage::slotUnitChanged( int u ) +{ + KoUnit::Unit unit = static_cast<KoUnit::Unit>( u ); + m_snapHorizUSpin->setUnit( unit ); + m_snapVertUSpin->setUnit( unit ); + m_spaceHorizUSpin->setUnit( unit ); + m_spaceVertUSpin->setUnit( unit ); +} + +void VConfigGridPage::apply() +{ + KarbonGridData &gd = m_view->part()->document().grid(); + gd.freq.setWidth( m_spaceHorizUSpin->value() ); + gd.freq.setHeight( m_spaceVertUSpin->value() ); + gd.snap.setWidth( m_snapHorizUSpin->value() ); + gd.snap.setHeight( m_snapVertUSpin->value() ); + gd.isShow = m_gridChBox->isChecked(); + gd.isSnap = m_snapChBox->isChecked(); + gd.color = m_gridColorBtn->color(); + m_view->repaintAll(); +} + +void VConfigGridPage::slotDefault() +{ + KoUnit::Unit unit = m_view->part()->document().unit(); + m_spaceHorizUSpin->setValue( KoUnit::toUserValue( 20.0, unit ) ); + m_spaceVertUSpin->setValue( KoUnit::toUserValue( 20.0, unit ) ); + m_snapHorizUSpin->setValue( KoUnit::toUserValue( 20.0, unit ) ); + m_snapVertUSpin->setValue( KoUnit::toUserValue( 20.0, unit ) ); + m_gridChBox->setChecked( true ); + m_snapChBox->setChecked( true ); + m_gridColorBtn->setColor( QColor( 228, 228, 228 ) ); +} + +VConfigDefaultPage::VConfigDefaultPage( KarbonView* view, + QVBox* box, char* name ) + : QObject( box->parent(), name ) +{ + m_view = view; + + m_config = KarbonFactory::instance()->config(); + + QVGroupBox* gbDocumentSettings = new QVGroupBox( + i18n( "Document Settings" ), box ); + gbDocumentSettings->setMargin( KDialog::marginHint() ); + gbDocumentSettings->setInsideSpacing( KDialog::spacingHint() ); + + m_oldAutoSave = m_view->part()->defaultAutoSave() / 60; + + m_oldBackupFile = true; + + m_oldSaveAsPath = true; + + if( m_config->hasGroup( "Interface" ) ) + { + m_config->setGroup( "Interface" ); + m_oldAutoSave = m_config->readNumEntry( "AutoSave", m_oldAutoSave ); + m_oldBackupFile = m_config->readBoolEntry( "BackupFile", m_oldBackupFile ); + m_oldSaveAsPath = m_config->readBoolEntry( "SaveAsPath", m_oldSaveAsPath ); + } + + m_autoSave = new KIntNumInput( m_oldAutoSave, gbDocumentSettings ); + m_autoSave->setRange( 0, 60, 1 ); + m_autoSave->setLabel( i18n( "Auto save (min):" ) ); + m_autoSave->setSpecialValueText( i18n( "No auto save" ) ); + m_autoSave->setSuffix( i18n( "min" ) ); + + m_createBackupFile = new QCheckBox( i18n( "Create backup file" ), gbDocumentSettings ); + m_createBackupFile->setChecked( m_oldBackupFile ); + + m_saveAsPath = new QCheckBox( i18n( "Save as path" ), gbDocumentSettings ); + m_saveAsPath->setChecked( m_oldSaveAsPath ); +} + +void VConfigDefaultPage::apply() +{ + m_config->setGroup( "Document defaults" ); + + m_config->setGroup( "Interface" ); + + int autoSave = m_autoSave->value(); + + if( autoSave != m_oldAutoSave ) + { + m_config->writeEntry( "AutoSave", autoSave ); + m_view->part()->setAutoSave( autoSave * 60 ); + m_oldAutoSave = autoSave; + } + + bool state = m_createBackupFile->isChecked(); + + if( state != m_oldBackupFile ) + { + m_config->writeEntry( "BackupFile", state ); + m_view->part()->setBackupFile( state ); + m_oldBackupFile = state; + } + + state = m_saveAsPath->isChecked(); + + //if( state != m_oldSaveAsPath ) + //{ + m_config->writeEntry( "SaveAsPath", state ); + m_view->part()->document().saveAsPath( state ); + m_oldSaveAsPath = state; + //} +} + +void VConfigDefaultPage::slotDefault() +{ + m_autoSave->setValue( m_view->part()->defaultAutoSave() / 60 ); + m_createBackupFile->setChecked( true ); + m_saveAsPath->setChecked( true ); +} + +#include "vconfiguredlg.moc" + diff --git a/karbon/dialogs/vconfiguredlg.h b/karbon/dialogs/vconfiguredlg.h new file mode 100644 index 00000000..f1470bea --- /dev/null +++ b/karbon/dialogs/vconfiguredlg.h @@ -0,0 +1,163 @@ +/* This file is part of the KDE project + Copyright (C) 2002, Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCONFIGUREDLG_H__ +#define __VCONFIGUREDLG_H__ + + +#include <kdialogbase.h> + +class KarbonView; +class KConfig; +class KIntNumInput; +class KColorButton; +class KoUnitDoubleSpinBox; +class QCheckBox; +class QComboBox; + +class VConfigInterfacePage : public QObject +{ + Q_OBJECT + +public: + VConfigInterfacePage( + KarbonView* view, QVBox *box = 0L, char* name = 0L ); + + void apply(); + +public slots: + void slotDefault(); + +private: + KarbonView* m_view; + KConfig* m_config; + + KIntNumInput* m_recentFiles; + int m_oldRecentFiles; + + QCheckBox* m_showStatusBar; + + KIntNumInput* m_copyOffset; + int m_oldCopyOffset; + + KIntNumInput* m_dockerFontSize; + int m_oldDockerFontSize; +}; + + +class VConfigMiscPage : public QObject +{ + Q_OBJECT + +public: + VConfigMiscPage( + KarbonView* view, QVBox* box, char* name = 0L ); + + void apply(); + +signals: + void unitChanged( int ); + +public slots: + void slotDefault(); + +private: + KarbonView* m_view; + KConfig* m_config; + + KIntNumInput* m_undoRedo; + int m_oldUndoRedo; + int m_oldUnit; + QComboBox *m_unit; +}; + +class VConfigDefaultPage : public QObject +{ + Q_OBJECT + +public: + VConfigDefaultPage( + KarbonView* view, QVBox* box, char* name = 0L ); + + void apply(); + +public slots: + void slotDefault(); + +private: + KarbonView* m_view; + KConfig* m_config; + + KIntNumInput* m_autoSave; + int m_oldAutoSave; + QCheckBox *m_createBackupFile; + bool m_oldBackupFile; + QCheckBox *m_saveAsPath; + bool m_oldSaveAsPath; +}; + +class VConfigGridPage : public QObject +{ + Q_OBJECT + +public: + VConfigGridPage( + KarbonView* view, QVBox* box, char* name = 0L ); + + void apply(); + +public slots: + void slotDefault(); + void slotUnitChanged( int ); + +protected slots: + void setMaxHorizSnap( double v ); + void setMaxVertSnap( double v ); + +private: + KarbonView* m_view; + KoUnitDoubleSpinBox* m_spaceHorizUSpin; + KoUnitDoubleSpinBox* m_spaceVertUSpin; + KoUnitDoubleSpinBox* m_snapHorizUSpin; + KoUnitDoubleSpinBox* m_snapVertUSpin; + QCheckBox* m_gridChBox; + QCheckBox* m_snapChBox; + KColorButton* m_gridColorBtn; +}; + +class VConfigureDlg : public KDialogBase +{ + Q_OBJECT + +public: + VConfigureDlg( KarbonView* parent ); + +public slots: + void slotApply(); + void slotDefault(); + +private: + VConfigInterfacePage* m_interfacePage; + VConfigMiscPage* m_miscPage; + VConfigGridPage* m_gridPage; + VConfigDefaultPage* m_defaultDocPage; +}; + +#endif + diff --git a/karbon/dialogs/vstrokedlg.cc b/karbon/dialogs/vstrokedlg.cc new file mode 100644 index 00000000..ed530178 --- /dev/null +++ b/karbon/dialogs/vstrokedlg.cc @@ -0,0 +1,216 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcombobox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qtabwidget.h> +#include <qradiobutton.h> +#include <qvbuttongroup.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kstandarddirs.h> + +#include "KoUnitWidgets.h" + +#include "karbon_part.h" +#include "vcolor.h" +#include "vselection.h" +#include "vstrokecmd.h" +#include "vstroke.h" +#include "vstrokedlg.h" +#include "vcolortab.h" + +VStrokeDlg::VStrokeDlg( KarbonPart* part, QWidget* parent, const char* name ) + : KDialogBase ( parent, name, true, i18n( "Stroke" ), Ok | Cancel ), m_part( part ) +{ + enableButtonSeparator( true ); + QTabWidget *mainWidget = new QTabWidget( this, "strokemain" ); + QHBoxLayout *mainLayout = new QHBoxLayout (mainWidget, 3); + + QVBoxLayout *leftLayout = new QVBoxLayout( mainLayout, 4 ); + + QLabel* widthLabel = new QLabel( i18n ( "stroke width", "Width:" ), mainWidget ); + leftLayout->addWidget ( widthLabel ); + m_setLineWidth = new KoUnitDoubleSpinBox( mainWidget, 0.0, 1000.0, 0.5, 1.0, KoUnit::U_PT, 1 ); + leftLayout->addWidget ( m_setLineWidth ); + + //Dashing -> + QLabel* styleLabel = new QLabel( i18n ( "Style:" ), mainWidget ); + leftLayout->addWidget ( styleLabel ); + m_styleCombo = new QComboBox( mainWidget ); + m_styleCombo->setEnabled ( false ); + leftLayout->addWidget ( m_styleCombo ); + // <- Dashing - reserved for later + + QRadioButton* button; + m_typeOption = new QVButtonGroup ( mainWidget ); + button = new QRadioButton ( i18n( "None" ), m_typeOption ); + m_typeOption->insert( button ); + button = new QRadioButton ( i18n( "Stroke" ), m_typeOption ); + m_typeOption->insert( button ); + button = new QRadioButton ( i18n( "Gradient" ), m_typeOption ); + m_typeOption->insert( button ); + m_typeOption->setTitle( i18n( "Type" ) ); + mainLayout->addWidget( m_typeOption ); + connect( m_typeOption, SIGNAL( clicked( int ) ), this, SLOT( slotTypeChanged( int ) ) ); + + m_capOption = new QVButtonGroup ( mainWidget ); + //button = new QRadioButton ( i18n( "Butt" ), m_capOption ); + button = new QRadioButton ( m_capOption ); + button->setPixmap( DesktopIcon( "cap_butt" ) ); + m_capOption->insert( button ); + button = new QRadioButton ( m_capOption ); + button->setPixmap( DesktopIcon( "cap_round" ) ); + m_capOption->insert( button ); + button = new QRadioButton ( m_capOption ); + button->setPixmap( DesktopIcon( "cap_square" ) ); + m_capOption->insert( button ); + m_capOption->setTitle( i18n( "Cap" ) ); + mainLayout->addWidget( m_capOption ); + connect( m_capOption, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + + m_joinOption = new QVButtonGroup ( mainWidget ); + button = new QRadioButton ( m_joinOption ); + button->setPixmap( DesktopIcon( "join_miter" ) ); + m_joinOption->insert( button ); + button = new QRadioButton ( m_joinOption ); + button->setPixmap( DesktopIcon( "join_round" ) ); + m_joinOption->insert( button ); + button = new QRadioButton ( m_joinOption ); + button->setPixmap( DesktopIcon( "join_bevel" ) ); + m_joinOption->insert( button ); + m_joinOption->setTitle( i18n( "Join" ) ); + mainLayout->addWidget( m_joinOption ); + connect( m_joinOption, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); + + VSelection *sel = part->document().selection(); + if( sel && sel->objects().count() > 0 ) // there is a selection, so take the stroke of first selected object + { + m_stroke.setType ( sel->objects().getFirst()->stroke()->type() ); + m_stroke.setColor ( sel->objects().getFirst()->stroke()->color() ); + m_stroke.setLineWidth ( sel->objects().getFirst()->stroke()->lineWidth() ); + m_stroke.setLineCap ( sel->objects().getFirst()->stroke()->lineCap() ); + m_stroke.setLineJoin ( sel->objects().getFirst()->stroke()->lineJoin() ); + m_stroke.setMiterLimit ( sel->objects().getFirst()->stroke()->miterLimit() ); + } + + slotUpdateDialog(); //Put the values of selected objects (or default) + mainLayout->activate(); + + //setMainWidget( mainWidget ); + + m_colortab = new VColorTab( sel->objects().count() == 0 ? sel->stroke()->color() : + sel->objects().getFirst()->stroke()->color(), this); + m_colortab->insertTab( mainWidget, i18n("Stroke"), 0 ); + m_colortab->setCurrentPage( 0 ); + + setMainWidget( m_colortab ); + + disableResize(); + connect (this, SIGNAL( okClicked( void ) ), this, SLOT( slotOKClicked ( void ) ) ); +} + +void VStrokeDlg::slotTypeChanged( int ID ) +{ + switch ( ID ) { + case 1: + m_stroke.setType ( VStroke::solid ); break; + case 2: + m_stroke.setType ( VStroke::grad ); break; + default: + m_stroke.setType ( VStroke::none ); + } +} + +void VStrokeDlg::slotCapChanged( int ID ) +{ + switch ( ID ) { + case 1: + m_stroke.setLineCap ( VStroke::capRound ); break; + case 2: + m_stroke.setLineCap ( VStroke::capSquare ); break; + default: + m_stroke.setLineCap ( VStroke::capButt ); + } +} + +void VStrokeDlg::slotJoinChanged( int ID ) +{ + switch ( ID ) { + case 1: + m_stroke.setLineJoin ( VStroke::joinRound ); break; + case 2: + m_stroke.setLineJoin ( VStroke::joinBevel ); break; + default: + m_stroke.setLineJoin ( VStroke::joinMiter ); + } +} + +void VStrokeDlg::slotOKClicked() +{ + m_stroke.setLineWidth ( m_setLineWidth->value() ); + + m_stroke.setColor( m_colortab->Color() ); + + if( m_part && m_part->document().selection()->objects().count() > 0 ) + m_part->addCommand( new VStrokeCmd( &m_part->document(), &m_stroke ), true ); + + emit strokeChanged( VStroke( m_stroke ) ); +} + +void VStrokeDlg::slotUpdateDialog() +{ + switch( m_stroke.type() ) + { + case VStroke::solid: + m_typeOption->setButton( 1 ); break; + case VStroke::grad: + m_typeOption->setButton( 2 ); break; + default: + m_typeOption->setButton( 0 ); + } + + switch( m_stroke.lineCap() ) + { + case VStroke::capRound: + m_capOption->setButton( 1 ); break; + case VStroke::capSquare: + m_capOption->setButton( 2 ); break; + default: + m_capOption->setButton( 0 ); + } + + switch( m_stroke.lineJoin() ) + { + case VStroke::joinRound: + m_joinOption->setButton( 1 ); break; + case VStroke::joinBevel: + m_joinOption->setButton( 2 ); break; + default: + m_joinOption->setButton( 0 ); + } + + m_setLineWidth->setValue( m_stroke.lineWidth() ); +} + +#include "vstrokedlg.moc" + diff --git a/karbon/dialogs/vstrokedlg.h b/karbon/dialogs/vstrokedlg.h new file mode 100644 index 00000000..ddfa1b9f --- /dev/null +++ b/karbon/dialogs/vstrokedlg.h @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTROKEDLG_H__ +#define __VSTROKEDLG_H__ + +#include <kdialogbase.h> + +class QComboBox; +class QVButtonGroup; + +class KarbonPart; +class KoUnitDoubleSpinBox; +class VStroke; +class VColorTab; + +class VStrokeDlg : public KDialogBase +{ + Q_OBJECT + +public: + VStrokeDlg( KarbonPart* part, QWidget* parent = 0L, const char* name = 0L ); + +private: + VColorTab* m_colortab; + KarbonPart *m_part; + KoUnitDoubleSpinBox *m_setLineWidth; + QComboBox *m_styleCombo; + QVButtonGroup *m_typeOption; + QVButtonGroup *m_capOption; + QVButtonGroup *m_joinOption; + +protected: + VStroke m_stroke; + +signals: + void strokeChanged( const VStroke & ); + +private slots: + void slotTypeChanged( int ID ); + void slotCapChanged( int ID ); + void slotJoinChanged( int ID ); + void slotOKClicked(); + void slotUpdateDialog(); + +}; + +#endif + diff --git a/karbon/dockers/Makefile.am b/karbon/dockers/Makefile.am new file mode 100644 index 00000000..9df79e8b --- /dev/null +++ b/karbon/dockers/Makefile.am @@ -0,0 +1,36 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../commands \ + -I$(srcdir)/../render \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../widgets \ + -I$(srcdir)/../dialogs \ + $(all_includes) + +noinst_LTLIBRARIES = \ + libkarbondockers.la + +noinst_HEADERS = \ + vcolordocker.h \ + vdocumentdocker.h \ + vstrokedocker.h \ + vstyledocker.h \ + vtransformdocker.h + +libkarbondockers_la_SOURCES = \ + dummy.cc \ + vcolordocker.cc \ + vdocumentdocker.cc \ + vstrokedocker.cc \ + vstyledocker.cc \ + vtransformdocker.cc + +libkarbondockers_la_METASOURCES = AUTO + +DISTCLEANFILES = \ + dummy.cc + +dummy.cc: + echo > dummy.cc + diff --git a/karbon/dockers/vcolordocker.cc b/karbon/dockers/vcolordocker.cc new file mode 100644 index 00000000..c5037967 --- /dev/null +++ b/karbon/dockers/vcolordocker.cc @@ -0,0 +1,283 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002 - 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qlayout.h> +#include <qtabwidget.h> +#include <qwidget.h> +#include <qcolor.h> +#include <qtooltip.h> +#include <qevent.h> +#include <qptrlist.h> + +#include <klocale.h> +#include <KoMainWindow.h> + +#include "karbon_part.h" +#include "karbon_view.h" +#include "karbon_factory.h" +#include "karbon_resourceserver.h" +#include "vcolor.h" +#include "vcolorslider.h" +#include "vselection.h" +#include "vfillcmd.h" +#include "vstrokecmd.h" +#include "vcommand.h" +#include "vobject.h" + +#include "vcolordocker.h" + +#include <ko_hsv_widget.h> +#include <ko_cmyk_widget.h> +#include <ko_rgb_widget.h> +#include <koColor.h> + +#include <kdebug.h> + +VColorDocker::VColorDocker( KarbonPart* part, KarbonView* parent, const char* /*name*/ ) + : QWidget(), m_part ( part ), m_view( parent ) +{ + m_isStrokeDocker = false; + setCaption( i18n( "Color Chooser" ) ); + + m_opacity = 1; + + m_fillCmd = 0; + m_strokeCmd = 0; + + mTabWidget = new QTabWidget( this ); + + /* ##### HSV WIDGET ##### */ + mHSVWidget = new KoHSVWidget( mTabWidget ); + connect( mHSVWidget, SIGNAL( sigFgColorChanged( const QColor &) ), this, SLOT( updateFgColor( const QColor &) ) ); + connect( mHSVWidget, SIGNAL( sigBgColorChanged( const QColor &) ), this, SLOT( updateBgColor( const QColor &) ) ); + connect(this, SIGNAL(fgColorChanged(const QColor &)), mHSVWidget, SLOT(setFgColor(const QColor &))); + connect(this, SIGNAL(bgColorChanged(const QColor &)), mHSVWidget, SLOT(setBgColor(const QColor &))); + connect( mHSVWidget, SIGNAL( sigModeChanged(KDualColorButton::DualColor) ), this, SLOT( updateMode( KDualColorButton::DualColor ) ) ); + mTabWidget->addTab( mHSVWidget, i18n( "HSV" ) ); + + /* ##### RGB WIDGET ##### */ + mRGBWidget = new KoRGBWidget( mTabWidget ); + connect( mRGBWidget, SIGNAL( sigFgColorChanged( const QColor &) ), this, SLOT( updateFgColor( const QColor &) ) ); + connect( mRGBWidget, SIGNAL( sigBgColorChanged( const QColor &) ), this, SLOT( updateBgColor( const QColor &) ) ); + connect(this, SIGNAL(fgColorChanged(const QColor &)), mRGBWidget, SLOT(setFgColor(const QColor &))); + connect(this, SIGNAL(bgColorChanged(const QColor &)), mRGBWidget, SLOT(setBgColor(const QColor &))); + connect( mRGBWidget, SIGNAL( sigModeChanged(KDualColorButton::DualColor) ), this, SLOT( updateMode( KDualColorButton::DualColor ) ) ); + mTabWidget->addTab( mRGBWidget, i18n( "RGB" ) ); + + /* ##### CMYK WIDGET ##### */ + /*mCMYKWidget = new KoCMYKWidget( mTabWidget ); + connect( mCMYKWidget, SIGNAL( sigFgColorChanged( const QColor &) ), this, SLOT( updateFgColor( const QColor &) ) ); + connect( mCMYKWidget, SIGNAL( sigBgColorChanged( const QColor &) ), this, SLOT( updateBgColor( const QColor &) ) ); + mTabWidget->addTab( mCMYKWidget, i18n( "CMYK" ) );*/ + + //Opacity + mOpacity = new VColorSlider( i18n( "Opacity:" ), QColor( "white" ), QColor( "black" ), 0, 100, 100, this ); + //TODO: Make "white" a transparent color + connect( mOpacity, SIGNAL( valueChanged ( int ) ), this, SLOT( updateOpacity() ) ); + QToolTip::add( mOpacity, i18n( "Alpha (opacity)" ) ); + + QVBoxLayout *mainWidgetLayout = new QVBoxLayout( this, 3 ); + mainWidgetLayout->addWidget( mTabWidget ); + mainWidgetLayout->addWidget( mOpacity ); + mainWidgetLayout->activate(); + setMaximumHeight( 174 ); + setMinimumWidth( 194 ); + +} + +VColorDocker::~VColorDocker() +{ +} + +void VColorDocker::updateFgColor(const QColor &c) +{ + m_color = c; + + VColor v = VColor(c); + v.setOpacity( m_opacity ); + + // check if we have objects selected + QPtrList<VObject> VNewObjectList = m_part->document().selection()->objects(); + if( ! VNewObjectList.count() ) + return; + + mHSVWidget->blockSignals(true); + mRGBWidget->blockSignals(true); + //mCMYKWidget->blockSignals(true); + + VCommandHistory* history = m_part->commandHistory(); + const QPtrList<VCommand>* commandList = history->commands(); + VStrokeCmd* command = dynamic_cast<VStrokeCmd*>(commandList->getLast()); + + if(command == 0 || m_strokeCmd == 0) + { + m_strokeCmd = new VStrokeCmd( &m_part->document(), v ); + m_part->addCommand( m_strokeCmd, true ); + } + else + { + QPtrList<VObject> VOldObjectList = command->getSelection()->objects(); + + if( VOldObjectList == VNewObjectList ) + { + m_strokeCmd->changeStroke(v); + m_part->repaintAllViews(); + } + else + { + m_strokeCmd = new VStrokeCmd( &m_part->document(), v ); + m_part->addCommand( m_strokeCmd, true ); + } + } + + emit fgColorChanged( c ); + + mHSVWidget->blockSignals(false); + mRGBWidget->blockSignals(false); + //mCMYKWidget->blockSignals(false); +} + +void VColorDocker::updateBgColor(const QColor &c) +{ + m_color = c; + + VColor v = VColor(c); + v.setOpacity( m_opacity ); + + // check if we have objects selected + QPtrList<VObject> VNewObjectList = m_part->document().selection()->objects(); + if( ! VNewObjectList.count() ) + return; + + mHSVWidget->blockSignals(true); + mRGBWidget->blockSignals(true); + //mCMYKWidget->blockSignals(true); + + VCommandHistory* history = m_part->commandHistory(); + const QPtrList<VCommand>* commandList = history->commands(); + VFillCmd* command = dynamic_cast<VFillCmd*>(commandList->getLast()); + + if(command == 0 || m_fillCmd == 0) + { + m_fillCmd = new VFillCmd( &m_part->document(), VFill(v) ); + m_part->addCommand( m_fillCmd, true ); + } + else + { + QPtrList<VObject> VOldObjectList = command->getSelection()->objects(); + + if( VOldObjectList == VNewObjectList ) + { + m_fillCmd->changeFill(VFill(v)); + m_part->repaintAllViews(); + } + else + { + m_fillCmd = new VFillCmd( &m_part->document(), VFill(v) ); + m_part->addCommand( m_fillCmd, true ); + } + } + + emit bgColorChanged( c ); + + mHSVWidget->blockSignals(false); + mRGBWidget->blockSignals(false); + //mCMYKWidget->blockSignals(false); +} + +void VColorDocker::updateOpacity() +{ + m_opacity = mOpacity->value() / 100.0; + + VColor c = VColor(m_color); + c.setOpacity( m_opacity ); + + if ( isStrokeDocker() ) + m_part->addCommand( new VStrokeCmd( &m_part->document(), c ), true ); + else + m_part->addCommand( new VFillCmd( &m_part->document(), VFill( c ) ), true ); +} + +void +VColorDocker::mouseReleaseEvent( QMouseEvent * ) +{ + //changeColor(); +} + +void VColorDocker::setFillDocker() +{ + m_isStrokeDocker = false; + mHSVWidget->setMode( KDualColorButton::Background ); + mRGBWidget->setMode( KDualColorButton::Background ); + update(); +} + +void VColorDocker::setStrokeDocker() +{ + m_isStrokeDocker = true; + mHSVWidget->setMode( KDualColorButton::Foreground ); + mRGBWidget->setMode( KDualColorButton::Foreground ); + update(); +} + +void VColorDocker::update() +{ + mHSVWidget->blockSignals(true); + mRGBWidget->blockSignals(true); + //mCMYKWidget->blockSignals(true); + + int objCnt = m_part->document().selection()->objects().count(); + + if( objCnt > 0 ) + { + VObject *obj = m_part->document().selection()->objects().getFirst(); + + QColor fgColor = QColor(obj->stroke() ? obj->stroke()->color() : VColor() ); + QColor bgColor = QColor(obj->fill() ? obj->fill()->color() : VColor() ); + + mHSVWidget->setFgColor(fgColor); + mRGBWidget->setFgColor(fgColor); + //mCMYKWidget->setFgColor(fgColor); + + mHSVWidget->setBgColor(bgColor); + mRGBWidget->setBgColor(bgColor); + //mCMYKWidget->setBgColor(bgColor); + + if( m_isStrokeDocker ) + m_color = fgColor; + else + m_color = bgColor; + } + + mHSVWidget->blockSignals(false); + mRGBWidget->blockSignals(false); + //mCMYKWidget->blockSignals(false); +} + +void VColorDocker::updateMode( KDualColorButton::DualColor s ) +{ + m_isStrokeDocker = (s == KDualColorButton::Foreground); + update(); + emit modeChanged( s ); +} + +#include "vcolordocker.moc" + diff --git a/karbon/dockers/vcolordocker.h b/karbon/dockers/vcolordocker.h new file mode 100644 index 00000000..e5e791d7 --- /dev/null +++ b/karbon/dockers/vcolordocker.h @@ -0,0 +1,80 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002 - 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOLORDOCKER_H__ +#define __VCOLORDOCKER_H__ + +class QTabWidget; +class QWidget; +class QColor; +class KarbonView; +class VColor; +class VColorSlider; +class KoHSVWidget; +class KoCMYKWidget; +class KoRGBWidget; + +class VColorDocker : public QWidget +{ + Q_OBJECT + +public: + VColorDocker( KarbonPart* part, KarbonView* parent = 0L, const char* name = 0L ); + virtual ~VColorDocker(); + + virtual bool isStrokeDocker() { return m_isStrokeDocker; }; + VColor color() { return m_color; } + +public slots: + virtual void setFillDocker(); + virtual void setStrokeDocker(); + virtual void update(); + +private: + virtual void mouseReleaseEvent( QMouseEvent *e ); + + QTabWidget *mTabWidget; + KoHSVWidget *mHSVWidget; + //KoCMYKWidget *mCMYKWidget; + KoRGBWidget *mRGBWidget; + VColorSlider *mOpacity; + +signals: + void fgColorChanged( const QColor &c ); + void bgColorChanged( const QColor &c ); + void modeChanged( KDualColorButton::DualColor s); +private slots: + void updateFgColor(const QColor &c); + void updateBgColor(const QColor &c); + void updateOpacity(); + void updateMode( KDualColorButton::DualColor s ); +protected: + bool m_isStrokeDocker; //Are we setting stroke color ( true ) or fill color ( false ) + QColor m_color; + float m_opacity; +private: + KarbonPart *m_part; + KarbonView *m_view; + VFillCmd *m_fillCmd; + VStrokeCmd *m_strokeCmd; +}; + +#endif + diff --git a/karbon/dockers/vdocumentdocker.cc b/karbon/dockers/vdocumentdocker.cc new file mode 100644 index 00000000..ccbbf711 --- /dev/null +++ b/karbon/dockers/vdocumentdocker.cc @@ -0,0 +1,1460 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qhbuttongroup.h> +#include <qinputdialog.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <qlistview.h> +#include <qptrvector.h> +#include <qtoolbutton.h> +#include <qpainter.h> +#include <qtabwidget.h> +#include <qlabel.h> +#include <qcursor.h> + +#include <klocale.h> +#include <kglobal.h> +#include <KoMainWindow.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <klineeditdlg.h> +#include <kinputdialog.h> + +#include "karbon_part.h" +#include "karbon_view.h" +#include "karbon_factory.h" +#include "karbon_resourceserver.h" +#include "vdocument.h" +#include "vkopainter.h" +#include "vlayer.h" +#include "vlayercmd.h" +#include "vdeletecmd.h" +#include "vzordercmd.h" +#include "vgroupcmd.h" +#include "vungroupcmd.h" +#include "vselection.h" +#include "vstroke.h" +#include "vcanvas.h" +#include "vdocumentdocker.h" +#include <visitors/vselectiondesc.h> + +static long g_lastKey = 0; + +/************************************************************************* + * Document tab * + *************************************************************************/ + +VDocumentPreview::VDocumentPreview( KarbonView* view, QWidget* parent ) + : QWidget( parent, "DocumentPreview" ), m_document( &view->part()->document() ), m_view( view ) +{ + update(); + installEventFilter( this ); + setBackgroundMode( Qt::NoBackground ); + setMouseTracking( true ); + m_dragging = false; + m_docpixmap = 0L; +} // VDocumentPreview::VDocumentPreview + +VDocumentPreview::~VDocumentPreview() +{ + delete m_docpixmap; +} // VDocumentPreview::~VDocumentPreview + +void +VDocumentPreview::reset() +{ + delete m_docpixmap; + m_docpixmap = 0L; +} + +bool +VDocumentPreview::eventFilter( QObject* object, QEvent* event ) +{ + double scaleFactor; + double xoffset = 0.; + double yoffset = 0.; + if ( ( height() - 4 ) / m_document->height() > ( width() - 4 ) / m_document->width() ) + { + scaleFactor = ( width() - 4 ) / m_document->width(); + yoffset = ( ( height() - 4 ) / scaleFactor - m_document->height() ) / 2; + } + else + { + scaleFactor = ( height() - 4 ) / m_document->height(); + xoffset = ( ( width() - 4 ) / scaleFactor - m_document->width() ) / 2; + } + KoRect rect = m_view->canvasWidget()->boundingBox(); + + QMouseEvent* mouseEvent = static_cast<QMouseEvent*>( event ); + if( event->type() == QEvent::MouseButtonPress ) + { + m_firstPoint.setX( mouseEvent->pos().x() ); + m_firstPoint.setY( mouseEvent->pos().y() ); + m_lastPoint = m_firstPoint; + KoPoint p3( m_firstPoint.x() / scaleFactor - xoffset, + ( height() - m_firstPoint.y() ) / scaleFactor - yoffset ); + m_dragging = rect.contains( p3 ); + } + else if( event->type() == QEvent::MouseButtonRelease ) + { + if( m_dragging ) + { + m_lastPoint.setX( mouseEvent->pos().x() ); + m_lastPoint.setY( mouseEvent->pos().y() ); + double dx = m_lastPoint.x() - m_firstPoint.x(); + double dy = m_lastPoint.y() - m_firstPoint.y(); + scaleFactor /= m_view->zoom(); + m_view->canvasWidget()->scrollBy( int( dx / scaleFactor ), int( dy / scaleFactor ) ); + m_firstPoint = m_lastPoint; + m_dragging = false; + update(); + } + } + else if( event->type() == QEvent::MouseMove ) + { + if( m_dragging ) + { + m_lastPoint.setX( mouseEvent->pos().x() ); + m_lastPoint.setY( mouseEvent->pos().y() ); + update(); + /*double dx = m_lastPoint.x() - m_firstPoint.x(); + double dy = m_lastPoint.y() - m_firstPoint.y(); + scaleFactor /= m_view->zoom(); + m_view->canvasWidget()->scrollBy( int( dx / scaleFactor ), int( dy / scaleFactor ) ); + m_firstPoint = m_lastPoint;*/ + } + else + { + KoPoint p3( mouseEvent->pos().x() / scaleFactor - xoffset, + ( height() - mouseEvent->pos().y() ) / scaleFactor - yoffset ); + setCursor( rect.contains( p3 ) ? QCursor::SizeAllCursor : QCursor( Qt::arrowCursor ) ); + } + } + + return QWidget::eventFilter( object, event ); +} + +void +VDocumentPreview::paintEvent( QPaintEvent* ) +{ + // TODO : use NotROP, otherwise too slow + QPixmap pixmap( width(), height() ); + double xoffset = 0.; + double yoffset = 0.; + double scaleFactor; + if ( ( height() - 4 ) / m_document->height() > ( width() - 4 ) / m_document->width() ) + { + scaleFactor = ( width() - 4 ) / m_document->width(); + yoffset = ( ( height() - 4 ) / scaleFactor - m_document->height() ) / 2; + } + else + { + scaleFactor = ( height() - 4 ) / m_document->height(); + xoffset = ( ( width() - 4 ) / scaleFactor - m_document->width() ) / 2; + } + xoffset += 2 / scaleFactor; + yoffset += 2 / scaleFactor; + if( !m_docpixmap || m_docpixmap->width() != width() || m_docpixmap->height() != height() ) + { + delete m_docpixmap; + m_docpixmap = new QPixmap( width(), height() ); + VKoPainter p( m_docpixmap, width(), height() ); + p.clear( QColor( 195, 194, 193 ) ); + p.setWorldMatrix( QWMatrix( 1, 0, 0, -1, xoffset * scaleFactor, height() - yoffset * scaleFactor ) ); + p.setZoomFactor( scaleFactor ); + KoRect rect( -xoffset, -yoffset, m_document->width() + xoffset, m_document->height() + yoffset ); + // draw doc outline + VColor c( Qt::black ); + VStroke stroke( c, 0L, 1.0 / scaleFactor ); + p.setPen( stroke ); + p.setBrush( Qt::white ); + p.drawRect( KoRect( 2, 2, m_document->width() - 2, m_document->height() - 2 ) ); + m_document->draw( &p, &rect ); + p.end(); + } + bitBlt( &pixmap, 0, 0, m_docpixmap, 0, 0, width(), height() ); + + // draw viewport rect + { + QPainter p( &pixmap ); + p.setWorldMatrix( QWMatrix( scaleFactor, 0, 0, -scaleFactor, xoffset * scaleFactor, height() - yoffset * scaleFactor ) ); + p.setPen( Qt::red ); + double dx = ( m_lastPoint.x() - m_firstPoint.x() ) * m_view->zoom(); + double dy = ( m_lastPoint.y() - m_firstPoint.y() ) * m_view->zoom(); + KoPoint p1( dx / scaleFactor, dy / scaleFactor ); + p1 = m_view->canvasWidget()->toContents( p1 ); + KoPoint p2( dx / scaleFactor + m_view->canvasWidget()->width(), dy / scaleFactor + m_view->canvasWidget()->height() ); + p2 = m_view->canvasWidget()->toContents( p2 ); + p.drawRect( int( p1.x() ), int( p1.y() ), int( p2.x() - p1.x() ), int( p2.y() - p1.y() ) ); + } + + QPainter pw( &pixmap ); + pw.setPen( colorGroup().light() ); + pw.drawLine( 1, 1, 1, height() - 2 ); + pw.drawLine( 1, 1, width() - 2, 1 ); + pw.drawLine( width() - 1, height() - 1, 0, height() - 1 ); + pw.drawLine( width() - 1, height() - 1, width() - 1, 0 ); + pw.setPen( colorGroup().dark() ); + pw.drawLine( 0, 0, width() - 1, 0 ); + pw.drawLine( 0, 0, 0, height() - 1 ); + pw.drawLine( width() - 2, height() - 2, width() - 2, 1 ); + pw.drawLine( width() - 2, height() - 2, 1, height() - 2 ); + pw.end(); + bitBlt( this, 0, 0, &pixmap, 0, 0, width(), height() ); +} // VDocumentPreview::paintEvent + +VDocumentTab::VDocumentTab( KarbonView* view, QWidget* parent ) + : QWidget( parent, "DocumentTab" ), m_view( view ) +{ + QFrame* frame; + QGridLayout* layout = new QGridLayout( this ); + layout->setMargin( 3 ); + layout->setSpacing( 2 ); + layout->addMultiCellWidget( m_documentPreview = new VDocumentPreview( m_view, this ), 0, 7, 2, 2 ); + layout->addWidget( new QLabel( i18n( "document width", "Width:" ), this ), 0, 0 ); + layout->addWidget( new QLabel( i18n( "Height:" ), this ), 1, 0 ); + layout->addMultiCellWidget( frame = new QFrame( this ), 2, 2, 0, 1 ); + frame->setFrameShape( QFrame::HLine ); + layout->addWidget( new QLabel( i18n( "Layers:" ), this ), 3, 0 ); + layout->addWidget( new QLabel( i18n( "Format:" ), this ), 4, 0 ); + layout->addMultiCellWidget( frame = new QFrame( this ), 5, 5, 0, 1 ); + frame->setFrameShape( QFrame::HLine ); + //layout->addMultiCellWidget( new QLabel( i18n( "Zoom factor:" ), this ), 6, 6, 0, 1 ); + layout->addWidget( m_width = new QLabel( this ), 0, 1 ); + layout->addWidget( m_height = new QLabel( this ), 1, 1 ); + layout->addWidget( m_layers = new QLabel( this ), 3, 1 ); + layout->addWidget( m_format = new QLabel( this ), 4, 1 ); + layout->setRowStretch( 7, 1 ); + layout->setColStretch( 0, 0 ); + layout->setColStretch( 1, 0 ); + layout->setColStretch( 2, 2 ); + //layout->addWidget( + + m_width->setAlignment( AlignRight ); + m_height->setAlignment( AlignRight ); + m_layers->setAlignment( AlignRight ); + m_format->setAlignment( AlignRight ); + + connect( view->part()->commandHistory(), SIGNAL( commandAdded( VCommand* ) ), this, SLOT( slotCommandAdded( VCommand* ) ) ); + connect( view->part()->commandHistory(), SIGNAL( commandExecuted() ), this, SLOT( slotCommandExecuted() ) ); + connect( view, SIGNAL( pageLayoutChanged() ), this, SLOT( slotCommandExecuted() ) ); + connect( view->canvasWidget(), SIGNAL( viewportChanged() ), this, SLOT( slotViewportChanged() ) ); + + updateDocumentInfo(); +} // VDocumentTab::VDocumentTab + +VDocumentTab::~VDocumentTab() +{ +} // VDocumentTab::~VDocumentTab + +void +VDocumentTab::updateDocumentInfo() +{ + m_width->setText( KoUnit::toUserStringValue( m_view->part()->document().width(), m_view->part()->unit() ) + m_view->part()->unitName() ); + m_height->setText( KoUnit::toUserStringValue( m_view->part()->document().height(), m_view->part()->unit() ) + m_view->part()->unitName() ); + m_layers->setText( QString::number( m_view->part()->document().layers().count() ) ); +} // VDocumentTab::updateDocumentInfo + +void +VDocumentTab::slotCommandAdded( VCommand * ) +{ + m_documentPreview->reset(); + m_documentPreview->update(); +} + +void +VDocumentTab::slotZoomChanged( double ) +{ + m_documentPreview->update(); +} + +void +VDocumentTab::slotViewportChanged() +{ + m_documentPreview->update(); + updateDocumentInfo(); +} + +void +VDocumentTab::slotCommandExecuted() +{ + m_documentPreview->reset(); + m_documentPreview->update(); +} + +/************************************************************************* + * Layers tab * + *************************************************************************/ + +VObjectListViewItem::VObjectListViewItem( QListViewItem* parent, VObject* object, VDocument *doc, uint key, QPtrDict<VObjectListViewItem> *map ) + : QListViewItem( parent, 0L ), m_object( object ), m_document( doc ), m_key( key ), m_map( map ) +{ + update(); + // add itself to object list item map + m_map->insert( object, this ); +} + +VObjectListViewItem::~VObjectListViewItem() +{ + // remove itself from object list item map + m_map->take( m_object ); +} + +QString +VObjectListViewItem::key( int, bool ) const +{ + return QString( "%1" ).arg( m_key ); +} + +void +VObjectListViewItem::update() +{ + // text description + VSelectionDescription selectionDesc; + selectionDesc.visit( *m_object ); + setText( 0, QString( "%1" ).arg( selectionDesc.shortDescription() ) ); + + // draw thumb preview (16x16) + QPixmap preview; + preview.resize( 16, 16 ); + VKoPainter p( &preview, 16, 16, false ); + // Y mirroring + QWMatrix mat; + mat.scale( 1, -1 ); + KoRect bbox = m_object->boundingBox(); + mat.translate( 0, -16 ); + double factor = 16. / kMax( bbox.width(), bbox.height() ); + mat.translate( -bbox.x() * factor, -bbox.y() * factor ); + p.setWorldMatrix( mat ); + + // TODO: When the document will support page size, change the following line. + p.setZoomFactor( factor ); + m_object->draw( &p ); + p.setZoomFactor( 1 ); + p.setWorldMatrix( QWMatrix() ); + p.setPen( Qt::black ); + p.setBrush( Qt::NoBrush ); + p.drawRect( KoRect( 0, 0, 16, 16 ) ); + p.end(); + + // set thumb preview, lock and visible pixmaps + setPixmap( 0, preview ); + QString s = ( m_object->state() == VObject::normal_locked || m_object->state() == VObject::hidden_locked ) ? "locked" : "unlocked"; + setPixmap( 1, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); + s = ( m_object->state() == VObject::hidden || m_object->state() == VObject::hidden_locked ) ? "14_layer_novisible" : "14_layer_visible"; + setPixmap( 2, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); +} + +int +VObjectListViewItem::compare( QListViewItem *i, int /*col*/, bool /*ascending*/ ) const +{ + VObjectListViewItem *objectItem = dynamic_cast<VObjectListViewItem*>(i); + if( ! objectItem ) return 0; + return m_key < objectItem->m_key ? -1 : 1; +} + +VLayerListViewItem::VLayerListViewItem( QListView* parent, VLayer* layer, VDocument *doc, QPtrDict<VLayerListViewItem> *map ) + : QCheckListItem( parent, 0L, CheckBox ), m_layer( layer ), m_document( doc), m_map( map ) +{ + update(); + // add itself to layer list item map + m_map->insert( layer, this ); +} // VLayerListViewItem::VLayerListViewItem + +VLayerListViewItem::~VLayerListViewItem() +{ + // remove itself from layer list item map + m_map->take( m_layer ); +} + +void +VLayerListViewItem::update() +{ + // draw thumb preview (16x16) + QPixmap preview; + preview.resize( 16, 16 ); + VKoPainter p( &preview, 16, 16, false ); + // Y mirroring + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -16 ); + p.setWorldMatrix( mat ); + + // TODO: When the document will support page size, change the following line. + p.setZoomFactor( 16. / 800. ); + m_layer->draw( &p ); + p.setZoomFactor( 1 ); + p.setWorldMatrix( QWMatrix() ); + p.setPen( Qt::black ); + p.setBrush( Qt::NoBrush ); + p.drawRect( KoRect( 0, 0, 16, 16 ) ); + p.end(); + + // text description + setOn( m_layer->selected() ); + setText( 0, m_layer->name() ); + + // set thumb preview, lock and visible pixmaps + setPixmap( 0, preview ); + QString s = ( m_layer->state() == VObject::normal_locked || m_layer->state() == VObject::hidden_locked ) ? "locked" : "unlocked"; + setPixmap( 1, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); + s = ( m_layer->state() == VObject::normal || m_layer->state() == VObject::normal_locked ) ? "14_layer_visible" : "14_layer_novisible"; + setPixmap( 2, *KarbonFactory::rServer()->cachePixmap( s, KIcon::Small ) ); +} // VLayerListViewItem::update + +void +VLayerListViewItem::stateChange( bool on ) +{ + m_layer->setSelected( on ); +} // VLayerListViewItem::stateChange + +int +VLayerListViewItem::pos() +{ + VLayerListViewItem* item; + if( !( item = (VLayerListViewItem*)itemAbove() ) ) + return 0; + else + return 1 + item->pos(); +} // VLayerListViewItem::pos + +QString +VLayerListViewItem::key( int, bool ) const +{ + return QString( "%1" ).arg( m_key ); +} + +int +VLayerListViewItem::compare( QListViewItem *i, int /*col*/, bool /*ascending*/ ) const +{ + VLayerListViewItem *layerItem = dynamic_cast<VLayerListViewItem*>(i); + if( ! layerItem ) return 0; + return m_key < layerItem->m_key ? -1 : 1; +} + +VLayersTab::VLayersTab( KarbonView* view, QWidget* parent ) + : QWidget( parent, "LayersTab" ), m_view( view ), m_document( &view->part()->document() ) +{ + + QToolButton* button; + QVBoxLayout* layout = new QVBoxLayout( this, 1 ); + layout->addWidget( m_layersListView = new QListView( this ), 1 ); + m_buttonGroup = new QHButtonGroup( this ); + m_buttonGroup->setInsideMargin( 3 ); + button = new QToolButton( m_buttonGroup ); + button->setIconSet( SmallIcon( "14_layer_newlayer" ) ); + button->setTextLabel( i18n( "New" ) ); + m_buttonGroup->insert( button ); + button = new QToolButton( m_buttonGroup ); + button->setIconSet( SmallIcon( "14_layer_raiselayer" ) ); + button->setTextLabel( i18n( "Raise" ) ); + m_buttonGroup->insert( button ); + button = new QToolButton( m_buttonGroup ); + button->setIconSet( SmallIcon( "14_layer_lowerlayer" ) ); + button->setTextLabel( i18n( "Lower" ) ); + m_buttonGroup->insert( button ); + button = new QToolButton( m_buttonGroup ); + button->setIconSet( SmallIcon( "14_layer_deletelayer" ) ); + button->setTextLabel( i18n( "Delete" ) ); + m_buttonGroup->insert( button ); + layout->addWidget( m_buttonGroup, 0); + layout->setSpacing( 0 ); + layout->setMargin( 3 ); + + m_layersListView->setAllColumnsShowFocus( true ); + m_layersListView->addColumn( i18n( "Item" ), 120 ); + m_layersListView->addColumn( i18n( "L" ), 20 ); + m_layersListView->addColumn( i18n( "V" ), 20 ); + m_layersListView->setColumnWidthMode( 0, QListView::Maximum ); + m_layersListView->setColumnAlignment( 1, Qt::AlignCenter ); + m_layersListView->setColumnAlignment( 2, Qt::AlignCenter ); + m_layersListView->setResizeMode( QListView::NoColumn ); + m_layersListView->setSorting( 0, false ); + m_layersListView->setRootIsDecorated( true ); + m_layersListView->setSelectionMode( QListView::Extended ); + + connect( m_layersListView, SIGNAL( clicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( itemClicked( QListViewItem*, const QPoint&, int ) ) ); + connect( m_layersListView, SIGNAL( rightButtonClicked( QListViewItem*, const QPoint&, int ) ), this, SLOT( renameItem( QListViewItem*, const QPoint&, int ) ) ); + connect( m_layersListView, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedFromList() ) ); + connect( m_view, SIGNAL( selectionChange() ), this, SLOT( selectionChangedFromTool() ) ); + connect( m_buttonGroup, SIGNAL( clicked( int ) ), this, SLOT( slotButtonClicked( int ) ) ); + connect( view->part()->commandHistory(), SIGNAL( commandExecuted( VCommand*) ), this, SLOT( slotCommandExecuted( VCommand* ) ) ); + + layout->activate(); + updateLayers(); +} // VLayersTab::VLayersTab + +VLayersTab::~VLayersTab() +{ +} // VLayersTab::~VLayersTab + +void +VLayersTab::slotButtonClicked( int ID ) +{ + switch( ID ) + { + case 0: + addLayer(); break; + case 1: + raiseItem(); break; + case 2: + lowerItem(); break; + case 3: + deleteItem(); break; + } +} // VLayersTab::slotButtonClicked + +void +VLayersTab::resetSelection() +{ + QListViewItemIterator it( m_layersListView ); + + // iterates over all list items and deselects them manually + // to avoid the list views selectionChanged signal + for(; it.current(); ++it ) + { + it.current()->setSelected( false ); + it.current()->repaint(); + } +} + +void +VLayersTab::selectActiveLayer() +{ + if( ! m_layers[ m_document->activeLayer() ] ) + { + QPtrVector<VLayer> vector; + m_document->layers().toVector( &vector ); + // find another layer to set active + for( int i = vector.count() - 1; i >= 0; i-- ) + if ( vector[i]->state() != VObject::deleted ) + { + m_document->setActiveLayer( vector[i] ); + break; + } + } + + // deselect all other layers + QPtrDictIterator<VLayerListViewItem> it( m_layers ); + for(; it.current(); ++it ) + { + it.current()->setSelected( false ); + it.current()->repaint(); + } + + VLayerListViewItem *layerItem = m_layers[ m_document->activeLayer() ]; + if( layerItem ) + { + layerItem->setSelected( true ); + layerItem->repaint(); + kdDebug(38000) << "selecting active layer: " << layerItem->text() << endl; + } +} + +void +VLayersTab::selectionChangedFromTool() +{ + resetSelection(); + removeDeletedObjectsFromList(); + + // TODO : use some kind of mapping... + VObjectListIterator itr = m_document->selection()->objects(); + for( ; itr.current(); ++itr ) + if( itr.current()->state() != VObject::deleted ) + { + VObject *obj = itr.current(); + + VObjectListViewItem *item = m_objects[ obj ]; + if( ! item ) + { + VLayerListViewItem *layerItem = m_layers[ obj->parent() ]; + if( layerItem ) + updateObjects( layerItem->layer(), layerItem ); + else + { + VObjectListViewItem *objectItem = m_objects[ obj->parent() ]; + if( objectItem ) + updateObjects( objectItem->object(), objectItem ); + else + continue; + } + item = m_objects[ obj ]; + } + if( ! item ) continue; + + item->setSelected( true ); + item->update(); + } + selectActiveLayer(); +} + +void +VLayersTab::updateChildItems( QListViewItem *item ) +{ + QListViewItemIterator it( item ); + + // iterator points to item, so make the next item current first + for( ++it; it.current(); ++it ) + { + VObjectListViewItem *objectItem = dynamic_cast<VObjectListViewItem *>( it.current() ); + if( ! objectItem ) continue; + + if( dynamic_cast<VGroup*>( objectItem->object() ) ) + updateChildItems( objectItem ); + + objectItem->update(); + objectItem->repaint(); + } +} + +void +VLayersTab::toggleState( VObject *obj, int col ) +{ + switch( col ) + { + case 1: // toggle visibility + if( obj->state() == VObject::hidden_locked ) + obj->setState( VObject::hidden ); + else if( obj->state() == VObject::normal_locked ) + obj->setState( VObject::selected ); + else if( obj->state() == VObject::normal || obj->state() >= VObject::selected ) + obj->setState( VObject::normal_locked ); + else if( obj->state() == VObject::hidden ) + obj->setState( VObject::hidden_locked ); + break; + case 2: // toggle locking + if( obj->state() == VObject::hidden_locked ) + obj->setState( VObject::normal_locked ); + else if( obj->state() == VObject::normal_locked ) + obj->setState( VObject::hidden_locked ); + else if( obj->state() == VObject::normal || obj->state() >= VObject::selected ) + obj->setState( VObject::hidden ); + else if( obj->state() == VObject::hidden ) + obj->setState( VObject::selected ); + break; + default: return; + } + + if( obj->state() < VObject::selected ) + m_document->selection()->take( *obj ); + else + m_document->selection()->append( obj ); +} + +void +VLayersTab::itemClicked( QListViewItem* item, const QPoint &, int col ) +{ + if( item ) + { + VLayerListViewItem *layerItem = dynamic_cast<VLayerListViewItem *>( item ); + if( layerItem ) + { + if( col == 0 ) + { + m_document->setActiveLayer( layerItem->layer() ); + selectActiveLayer(); + } + if( col > 0 ) + { + toggleState( layerItem->layer(), col ); + + layerItem->update(); + layerItem->repaint(); + + updateChildItems( layerItem ); + + m_view->part()->repaintAllViews(); + } + } + else + { + VObjectListViewItem *objectItem = dynamic_cast< VObjectListViewItem *>( item ); + + if( col == 0 ) + { + VObject *obj = objectItem->object(); + if( obj->state() == VObject::normal ) + obj->setState( VObject::selected ); + } + if( col > 0 ) + { + toggleState( objectItem->object(), col ); + + if( objectItem->object()->state() == VObject::selected ) + objectItem->setSelected( true ); + else + objectItem->setSelected( false ); + + objectItem->update(); + objectItem->repaint(); + + if( dynamic_cast<VGroup*>( objectItem->object() ) ) + updateChildItems( objectItem ); + + m_view->part()->repaintAllViews(); + } + } + } +} // VLayersTab::itemClicked + +void +VLayersTab::selectionChangedFromList() +{ + m_document->selection()->clear(); + + QListViewItemIterator it( m_layersListView ); + + // iterate over all list items and add their corresponding object + // to the documents selection if the list item is selected and not hidden or locked or both + for(; it.current(); ++it ) + { + VObjectListViewItem *objectItem = dynamic_cast<VObjectListViewItem *>( it.current() ); + if( ! objectItem ) continue; + + VObject::VState state = objectItem->object()->state(); + + if( state == VObject::deleted ) + { + delete objectItem; + continue; + } + + if( objectItem->isSelected() && (state != VObject::hidden) && (state != VObject::normal_locked ) + && (state != VObject::hidden_locked) ) + { + m_document->selection()->append( objectItem->object() ); + objectItem->repaint(); + } + } + + m_view->selectionChanged(); + m_view->part()->repaintAllViews(); +} + +void +VLayersTab::renameItem( QListViewItem* item, const QPoint&, int col ) +{ + if ( ( item ) && col == 0 ) + { + bool ok = true; + VLayerListViewItem* layerItem = dynamic_cast<VLayerListViewItem *>( item ); + if( !layerItem ) + { + VObjectListViewItem *objectItem = dynamic_cast< VObjectListViewItem *>( item ); + VObject *obj = objectItem->object(); + QString name = KInputDialog::getText( i18n( "Current Object" ), i18n( "Change the name of the object:" ), + obj->name(), &ok, this ); + if( ok ) + { + m_document->setObjectName( obj, name ); + objectItem->update(); + } + } + else + { + QString name = KInputDialog::getText( i18n( "Rename Layer" ), i18n( "Change the name of the current layer:" ), + layerItem->layer()->name(), &ok, this ); + if( ok ) + { + layerItem->layer()->setName( name ); + layerItem->update(); + } + } + } +} // VLayersTab::renameItem + +void +VLayersTab::addLayer() +{ + bool ok = true; + QString name = KInputDialog::getText( i18n( "New Layer" ), i18n( "Enter the name of the new layer:" ), + i18n( "New layer" ), &ok, this ); + if( ok ) + { + VLayer* layer = new VLayer( m_document ); + layer->setName( name ); + VLayerCmd* cmd = new VLayerCmd( m_document, i18n( "Add Layer" ), + layer, VLayerCmd::addLayer ); + m_view->part()->addCommand( cmd, true ); + updateLayers(); + } +} // VLayersTab::addLayer + +void +VLayersTab::raiseItem() +{ + VCommand *cmd = 0L; + //QListViewItem *newselection = 0L; + QListViewItemIterator it( m_layersListView ); + + if( m_document->selection()->objects().count() ) + { + cmd = new VZOrderCmd( m_document, VZOrderCmd::up ); + m_view->part()->addCommand( cmd, true ); + } + else + { + for(; it.current(); ++it ) + { + if( ! it.current()->isSelected() ) continue; + + VLayerListViewItem* layerItem = dynamic_cast<VLayerListViewItem *>( it.current() ); + if( layerItem ) + { + VLayer *layer = layerItem->layer(); + if( layer && m_document->canRaiseLayer( layer ) ) + { + cmd = new VLayerCmd( m_document, i18n( "Raise Layer" ), + layerItem->layer(), VLayerCmd::raiseLayer ); + m_view->part()->addCommand( cmd, true ); + } + } + } + } + + if( cmd ) updatePreviews(); +} // VLayersTab::raiseItem + +void +VLayersTab::lowerItem() +{ + VCommand *cmd = 0L; + QListViewItemIterator it( m_layersListView ); + + if( m_document->selection()->objects().count() ) + { + cmd = new VZOrderCmd( m_document, VZOrderCmd::down ); + m_view->part()->addCommand( cmd, true ); + } + else + { + for(; it.current(); ++it ) + { + if( ! it.current()->isSelected() ) continue; + + VLayerListViewItem* layerItem = dynamic_cast<VLayerListViewItem *>( it.current() ); + if( layerItem ) + { + VLayer *layer = layerItem->layer(); + if( layer && m_document->canLowerLayer( layer ) ) + { + cmd = new VLayerCmd( m_document, i18n( "Lower Layer" ), layer, VLayerCmd::lowerLayer ); + m_view->part()->addCommand( cmd, true ); + } + } + } + } + + if( cmd ) updatePreviews(); +} // VLayersTab::lowerItem + +void +VLayersTab::deleteItem() +{ + VCommand *cmd = 0L; + QListViewItemIterator it( m_layersListView ); + + QPtrList<QListViewItem> deleteItems; + deleteItems.setAutoDelete( false ); + + // collect all selected items because they get deselected + // when the first item is removed + for(; it.current(); ++it ) + { + if( ! it.current()->isSelected() ) continue; + deleteItems.append( it.current() ); + } + + for( ;deleteItems.first(); ) + { + VLayerListViewItem* layerItem = dynamic_cast< VLayerListViewItem *>( deleteItems.current() ); + if( layerItem ) + { + VLayer *layer = layerItem->layer(); + if( layer && m_layers.count() > 1 ) + { + cmd = new VLayerCmd( m_document, i18n( "Delete Layer" ), layer, VLayerCmd::deleteLayer ); + + VObjectListIterator itr = layer->objects(); + // iterate over this layers child objects and remove them from the internal + // object list and the list of the to be deleted items + for( ; itr.current(); ++itr ) + { + VObjectListViewItem *objectItem = m_objects.take( itr.current() ); + deleteItems.remove( objectItem ); + } + + delete layerItem; + + m_view->part()->addCommand( cmd ); + + selectActiveLayer(); + } + } + else + { + VObjectListViewItem* item = dynamic_cast< VObjectListViewItem *>( deleteItems.current() ); + if( item ) + { + cmd = new VDeleteCmd( m_document, item->object() ); + + delete item; + + m_view->part()->addCommand( cmd ); + } + } + // remove first item, next item becomes current + deleteItems.removeFirst(); + } + if( cmd ) + { + updatePreviews(); + m_view->part()->repaintAllViews(); + } +} // VLayersTab::deleteItem + +void +VLayersTab::updatePreviews() +{ + // TODO: Optimization: call update() on each view item... + updateLayers(); +} // VLayersTab::updatePreviews + +void +VLayersTab::updateLayers() +{ + removeDeletedObjectsFromList(); + + QPtrVector<VLayer> vector; + m_document->layers().toVector( &vector ); + VLayerListViewItem* item = 0L; + for( int i = vector.count() - 1; i >= 0; i-- ) + { + if ( vector[i]->state() != VObject::deleted ) + { + if( !m_layers[ vector[i] ] ) + { + item = new VLayerListViewItem( m_layersListView, vector[i], m_document, &m_layers ); + item->setOpen( true ); + } + else + item = m_layers[ vector[i] ]; + + item->setKey(i); + + updateObjects( vector[i], item ); + } + } + + selectActiveLayer(); + m_layersListView->sort(); +} // VLayersTab::updateLayers + +void +VLayersTab::updateObjects( VObject *object, QListViewItem *item ) +{ + VObjectListIterator itr = dynamic_cast<VGroup *>( object )->objects(); + + for( uint objcount = 1; itr.current(); ++itr, objcount++ ) + if( itr.current()->state() != VObject::deleted ) + { + VObjectListViewItem *objectItem = m_objects[ itr.current() ]; + if( ! objectItem ) + { + // object not found -> insert + objectItem = new VObjectListViewItem( item, itr.current(), m_document, objcount, &m_objects ); + objectItem->update(); + } + else if( objectItem->parent() != item ) + { + // object found, but has false parent -> reparent + objectItem->parent()->takeItem( objectItem ); + item->insertItem( objectItem ); + } + + objectItem->setKey( objcount ); + + if( dynamic_cast<VGroup *>( itr.current() ) ) + updateObjects( itr.current(), objectItem ); + } + + item->sort(); +} + +void +VLayersTab::removeDeletedObjectsFromList() +{ + QPtrDictIterator<VObjectListViewItem> it( m_objects ); + + // iterate over all object items and delete the following items: + // - items representing deleted objects + // - items with objects objects that changed parents + // BEWARE: when deleting an item, the iterator is automatically incremented + for(; it.current(); ) + { + VLayerListViewItem *layerItem = dynamic_cast<VLayerListViewItem*>( it.current()->parent() ); + if( layerItem ) + { + VGroup *group = dynamic_cast<VGroup*>( layerItem->layer() ); + // check if object of item is still child of object of parent item + if( group && ! group->objects().contains( it.current()->object() ) ) + { + layerItem->takeItem( it.current() ); + delete it.current(); + continue; + } + } + else + { + VObjectListViewItem *objectItem = dynamic_cast<VObjectListViewItem*>( it.current()->parent() ); + if( objectItem ) + { + VGroup *group = dynamic_cast<VGroup*>( objectItem->object() ); + // check if object of item is still child of object of parent item + if( group && ! group->objects().contains( it.current()->object() ) ) + { + objectItem->takeItem( it.current() ); + delete it.current(); + continue; + } + } + else + { + delete it.current(); + continue; + } + } + + if( it.current()->object()->state() == VObject::deleted ) + { + delete it.current(); + continue; + } + + ++it; + } + + QPtrDictIterator<VLayerListViewItem> itr( m_layers ); + + // iterate over all layer items and delete the following items: + // - items representing deleted layers + // BEWARE: when deleting an item, the iterator is automatically incremented + for(; itr.current(); ) + { + if( itr.current()->layer()->state() == VObject::deleted ) + { + m_layersListView->takeItem( itr.current() ); + delete itr.current(); + continue; + } + ++itr; + } +} + + +void +VLayersTab::slotCommandExecuted( VCommand* command ) +{ + // sync listview on changing layers or deleting/undeleting or grouping/ungrouping objects + if( dynamic_cast<VLayerCmd*>( command ) + || dynamic_cast<VDeleteCmd*>( command ) + || dynamic_cast<VGroupCmd*>( command ) + || dynamic_cast<VUnGroupCmd*>( command ) + || dynamic_cast<VZOrderCmd*>( command ) ) + updateLayers(); +} + +/************************************************************************* + * History tab * + *************************************************************************/ + +VHistoryGroupItem::VHistoryGroupItem( VHistoryItem* item, QListView* parent, QListViewItem* after ) + : QListViewItem( parent, after ) +{ + setPixmap( 0, *item->pixmap( 0 ) ); + setText( 0, item->text( 0 ) ); + parent->takeItem( item ); + insertItem( item ); + m_key = item->key( 0, true ); +} // VHistoryItem::VHistoryItem + +VHistoryGroupItem::~VHistoryGroupItem() +{ +} // VHistoryGroupItem::~VHistoryGroupItem + +void +VHistoryGroupItem::paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) +{ + int e = 0; + int n = 0; + VHistoryItem* item = (VHistoryItem*)firstChild(); + while ( item ) + { + if ( item->command()->success() ) + e++; + else + n++; + item = (VHistoryItem*)item->nextSibling(); + } + if ( e > 0 ) + { + p->fillRect( 0, 0, width, height(), cg.base() ); + if ( n > 0 ) + p->fillRect( 0, 0, width, height(), QBrush( cg.base().dark( 140 ), QBrush::BDiagPattern ) ); + } + else + p->fillRect( 0, 0, width, height(), cg.base().dark( 140 ) ); + + const QPixmap* pixmap = this->pixmap( column ); + int xstart; + if ( pixmap ) + { + int pw = pixmap->width(); + int ph = pixmap->height(); + p->drawPixmap( ( height() - pw ) / 2, ( height() - ph ) / 2, *pixmap ); + xstart = height(); + } + else + xstart = 4; + p->setPen( cg.text() ); + p->drawText( xstart, 0, width - xstart, height(), align | Qt::AlignVCenter, text( column ) ); +} // VHistoryGroupItem::paintCell + +void +VHistoryGroupItem::paintFocus( QPainter*, const QColorGroup&, const QRect& ) +{ + // Do not paint any focus rectangle + // It makes the list and the selected item look messy + +} // VHistoryGroupItem::paintFocus + +VHistoryItem::VHistoryItem( VCommand* command, QListView* parent, QListViewItem* after ) + : QListViewItem( parent, after ), m_command( command ) +{ + init(); +} // VHistoryItem::VHistoryItem + +VHistoryItem::VHistoryItem( VCommand* command, VHistoryGroupItem* parent, QListViewItem* after ) + : QListViewItem( parent, after ), m_command( command ) +{ + init(); +} // VHistoryItem::VHistoryItem + +void +VHistoryItem::init() +{ + kdDebug(38000) << "In VHistoryItem::init() : " << m_command->name() << endl; + char buffer[70]; + sprintf( buffer, "%064ld", ++g_lastKey ); + m_key = buffer; + setPixmap( 0, QPixmap( KGlobal::iconLoader()->iconPath( m_command->icon(), KIcon::Small ) ) ); + setText( 0, m_command->name() ); +} // VHistoryITem::init + +VHistoryItem::~VHistoryItem() +{ +} // VHistoryItem::~VHistoryItem + +void +VHistoryItem::paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ) +{ + p->fillRect( 0, 0, width, height(), ( m_command->success() ? cg.base() : cg.base().dark( 140 ) ) ); + + const QPixmap* pixmap = this->pixmap( column ); + int xstart; + if ( pixmap ) + { + int pw = pixmap->width(); + int ph = pixmap->height(); + p->drawPixmap( ( height() - pw ) / 2, ( height() - ph ) / 2, *pixmap ); + xstart = height(); + } + else + xstart = 4; + p->setPen( cg.text() ); + p->drawText( xstart, 0, width - xstart, height(), align | Qt::AlignVCenter, text( column ) ); +} // VHistoryItem::paintCell + +void +VHistoryItem::paintFocus( QPainter*, const QColorGroup&, const QRect& ) +{ + // Do not paint any focus rectangle + // It makes the list and the selected item look messy + +} // VHistoryItem::paintFocus + +VHistoryTab::VHistoryTab( KarbonPart* part, QWidget* parent ) + : QWidget( parent ), m_part( part ) +{ + QVBoxLayout* layout = new QVBoxLayout( this ); + layout->setMargin( 3 ); + layout->setSpacing( 2 ); + layout->add( m_history = new QListView( this ) ); + m_history->setVScrollBarMode( QListView::AlwaysOn ); + m_history->setSelectionMode( QListView::NoSelection ); + m_history->addColumn( i18n( "Commands" ) ); + m_history->setResizeMode( QListView::AllColumns ); + m_history->setRootIsDecorated( true ); + layout->add( m_groupCommands = new QCheckBox( i18n( "Group commands" ), this ) ); + + m_history->setSorting( 0, true ); + VHistoryGroupItem* group = 0; + VHistoryItem* last = 0; + QPtrVector<VCommand> cmds; + part->commandHistory()->commands()->toVector( &cmds ); + int c = cmds.count(); + for ( int i = 0; i < c; i++ ) + { + if ( ( i > 0 ) && ( cmds[ i ]->name() == cmds[ i - 1 ]->name() ) ) + if ( group ) + { + QListViewItem* prev = group->firstChild(); + while ( prev && prev->nextSibling() ) + prev = prev->nextSibling(); + new VHistoryItem( cmds[ i ], group, prev ); + } + else + { + group = new VHistoryGroupItem( last, m_history, last ); + new VHistoryItem( cmds[ i ], group, last ); + } + else + { + last = new VHistoryItem( cmds[ i ], m_history, last ); + group = 0; + } + } + m_history->sort(); + + connect( m_history, SIGNAL( mouseButtonClicked( int, QListViewItem*, const QPoint&, int ) ), this, SLOT( commandClicked( int, QListViewItem*, const QPoint&, int ) ) ); + connect( m_groupCommands, SIGNAL( stateChanged( int ) ), this, SLOT( groupingChanged( int ) ) ); + connect( part->commandHistory(), SIGNAL( historyCleared() ), this, SLOT( historyCleared() ) ); + connect( part->commandHistory(), SIGNAL( commandAdded( VCommand* ) ), this, SLOT( slotCommandAdded( VCommand* ) ) ); + connect( part->commandHistory(), SIGNAL( commandExecuted( VCommand* ) ), this, SLOT( commandExecuted( VCommand* ) ) ); + connect( part->commandHistory(), SIGNAL( firstCommandRemoved() ), this, SLOT( removeFirstCommand() ) ); + connect( part->commandHistory(), SIGNAL( lastCommandRemoved() ), this, SLOT( removeLastCommand() ) ); + connect( this, SIGNAL( undoCommand( VCommand* ) ), part->commandHistory(), SLOT( undo( VCommand* ) ) ); + connect( this, SIGNAL( redoCommand( VCommand* ) ), part->commandHistory(), SLOT( redo( VCommand* ) ) ); + connect( this, SIGNAL( undoCommandsTo( VCommand* ) ), part->commandHistory(), SLOT( undoAllTo( VCommand* ) ) ); + connect( this, SIGNAL( redoCommandsTo( VCommand* ) ), part->commandHistory(), SLOT( redoAllTo( VCommand* ) ) ); +} // VHistoryTab::VHistoryTab + +VHistoryTab::~VHistoryTab() +{ +} // VHistoryTab::~VHistoryTab + +bool +VHistoryTab::groupingEnabled() +{ + return m_groupCommands->isChecked(); +} // VHistoryTab::groupingEnabled + +void +VHistoryTab::historyCleared() +{ + m_history->clear(); +} // VHistoryTab::historyCleared + +void +VHistoryTab::commandExecuted( VCommand* command ) +{ + QListViewItem* item = m_history->firstChild(); + bool found = false; + while ( !found && item ) + { + if ( item->rtti() == 1001 ) + { + QListViewItem* child = item->firstChild(); + while ( !found && child ) + { + found = ( ( (VHistoryItem*)child )->command() == command ); + if ( !found ) + child = child->nextSibling(); + else + item = child; + } + } + found = ( item && ( (VHistoryItem*)item )->command() == command ); + if ( !found ) + item = item->nextSibling(); + } + if ( found ) + { + m_history->repaintItem( item ); + if ( item->parent() ) + m_history->repaintItem( item->parent() ); + m_history->ensureItemVisible( item ); + } +} // VHistoryTab::commandExecuted + +void +VHistoryTab::slotCommandAdded( VCommand* command ) +{ + if ( !command ) + return; + + QListViewItem* last = m_history->firstChild(); + while ( last && last->nextSibling() ) + last = last->nextSibling(); + + if( groupingEnabled() ) + { + if( ( last ) && last->text( 0 ) == command->name() ) + { + if( last->rtti() == 1002 ) + { + QListViewItem* prevSibling; + if( m_history->childCount() > 1 ) + { + prevSibling = m_history->firstChild(); + while ( prevSibling->nextSibling() != last ) + prevSibling = prevSibling->nextSibling(); + } + else + prevSibling = m_history->firstChild(); + last = new VHistoryGroupItem( (VHistoryItem*)last, m_history, prevSibling ); + } + QListViewItem* prev = last->firstChild(); + while ( prev && prev->nextSibling() ) + prev = prev->nextSibling(); + m_history->setCurrentItem( new VHistoryItem( command, (VHistoryGroupItem*)last, prev ) ); + } + else + m_history->setCurrentItem( new VHistoryItem( command, m_history, last ) ); + } + else + m_history->setCurrentItem( new VHistoryItem( command, m_history, last ) ); + + m_history->sort(); + m_history->ensureItemVisible( m_history->currentItem() ); + m_history->update(); +} // VHistoryTab::slotCommandAdded + +void +VHistoryTab::removeFirstCommand() +{ + if ( m_history->childCount() > 0 ) + if ( m_history->firstChild()->rtti() == 1002 ) + delete m_history->firstChild(); + else + { + VHistoryGroupItem* group = (VHistoryGroupItem*)m_history->firstChild(); + delete group->firstChild(); + if ( group->childCount() == 1 ) + { + new VHistoryItem( ( (VHistoryItem*)group->firstChild() )->command(), m_history, 0 ); + delete group; + } + } +} // VHistoryTab::removeFirstCommand + +void +VHistoryTab::removeLastCommand() +{ + if ( m_history->childCount() > 0 ) + { + QListViewItem* last = m_history->firstChild(); + while ( last && last->nextSibling() ) + last = last->nextSibling(); + if ( last->rtti() == 1002 ) + delete last; + else + { + VHistoryGroupItem* group = (VHistoryGroupItem*)last; + last = group->firstChild(); + while ( last && last->nextSibling() ) + last = last->nextSibling(); + delete last; + if ( group->childCount() == 1 ) + { + new VHistoryItem( ( (VHistoryItem*)group->firstChild() )->command(), m_history, group ); + delete group; + } + } + } +} // VHistoryTab::removeLastCommand + +void +VHistoryTab::commandClicked( int button, QListViewItem* item, const QPoint&, int ) +{ + if ( !item || item->rtti() == 1001 ) + return; + + VCommand* cmd = ( (VHistoryItem*)item )->command(); + if ( cmd->success() ) + if ( button == 1 ) + emit undoCommandsTo( ( (VHistoryItem*)item )->command() ); + else + emit undoCommand( ( (VHistoryItem*)item )->command() ); + else + if ( button == 1 ) + emit redoCommandsTo( ( (VHistoryItem*)item )->command() ); + else + emit redoCommand( ( (VHistoryItem*)item )->command() ); +} // VHistoryTab::commandClicked + +void +VHistoryTab::groupingChanged( int ) +{ + if ( m_groupCommands->isChecked() && m_history->childCount() > 1 ) + { + QListViewItem* s2last = 0; + QListViewItem* last = m_history->firstChild(); + QListViewItem* item = last->nextSibling(); + while ( item ) + if ( last->text( 0 ) == item->text( 0 ) ) + { + if ( last->rtti() == 1002 ) + last = new VHistoryGroupItem( (VHistoryItem*)last, m_history, s2last ); + m_history->takeItem( item ); + last->insertItem( item ); + item = last->nextSibling(); + } + else + { + s2last = last; + last = item; + item = last->nextSibling(); + } + } + else + { + QListViewItem* item = m_history->firstChild(); + while ( item ) + if ( item->rtti() == 1001 ) + { + QListViewItem* child; + while ( ( child = item->firstChild() ) ) + { + item->takeItem( child ); + m_history->insertItem( child ); + } + child = item; + item = item->nextSibling(); + delete child; + } + else + item = item->nextSibling(); + } + m_history->sort(); + m_history->update(); +} // VHistoryTab::groupingChanged + +#include "vdocumentdocker.moc" diff --git a/karbon/dockers/vdocumentdocker.h b/karbon/dockers/vdocumentdocker.h new file mode 100644 index 00000000..278f56ba --- /dev/null +++ b/karbon/dockers/vdocumentdocker.h @@ -0,0 +1,256 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VDOCUMENTDOCKER_H__ +#define __VDOCUMENTDOCKER_H__ + +#include <qlistview.h> +#include <qptrdict.h> + +class QHButtonGroup; +class QPoint; +class QLabel; +class QPixmap; +class QCheckBox; + +class VDocument; +class VLayer; +class KarbonView; + +/************************************************************************* + * Document Tab * + *************************************************************************/ + +class VDocumentPreview : public QWidget +{ + Q_OBJECT + + public: + VDocumentPreview( KarbonView* view, QWidget* parent = 0 ); + ~VDocumentPreview(); + + void reset(); + + protected: + void paintEvent( QPaintEvent* e ); + virtual bool eventFilter( QObject* object, QEvent* event ); + + private: + VDocument *m_document; + KarbonView *m_view; + KoPoint m_firstPoint; + KoPoint m_lastPoint; + bool m_dragging; + QPixmap *m_docpixmap; +}; // VDocumentPreview + +class VDocumentTab : public QWidget +{ + Q_OBJECT + + public: + VDocumentTab( KarbonView* view, QWidget* parent ); + ~VDocumentTab(); + + public slots: + void updateDocumentInfo(); + void slotCommandAdded( VCommand* command ); + void slotZoomChanged( double ); + void slotViewportChanged(); + void slotCommandExecuted(); + + private: + VDocumentPreview* m_documentPreview; + QLabel* m_height; + QLabel* m_width; + QLabel* m_layers; + QLabel* m_format; + + KarbonView* m_view; +}; // VDocumentTab + +/************************************************************************* + * Layers Tab * + *************************************************************************/ + +class VLayerListViewItem : public QCheckListItem +{ +public: + VLayerListViewItem( QListView* parent, VLayer* layer, VDocument *doc, QPtrDict<VLayerListViewItem> *map ); + virtual ~VLayerListViewItem(); + + VLayer* layer() { return m_layer; } + int pos(); + void update(); + virtual QString key( int column, bool ascending ) const; + virtual int compare( QListViewItem *i, int col, bool ascending ) const; + void setKey( uint key ) { m_key = key; } + +protected: + virtual void stateChange( bool on ); + +private: + VLayer *m_layer; + VDocument *m_document; + uint m_key; + QPtrDict<VLayerListViewItem> *m_map; +}; // VLayerListViewItem + +class VObjectListViewItem : public QListViewItem +{ +public: + VObjectListViewItem( QListViewItem* parent, VObject* object, VDocument *doc, uint key, QPtrDict<VObjectListViewItem> *map ); + virtual ~VObjectListViewItem(); + + VObject* object() { return m_object; } + void update(); + virtual QString key( int column, bool ascending ) const; + virtual int compare( QListViewItem *i, int col, bool ascending ) const; + void setKey( uint key ) { m_key = key; } +private: + VObject *m_object; + VDocument *m_document; + uint m_key; + QPtrDict<VObjectListViewItem> *m_map; +}; + +class VLayersTab : public QWidget +{ +Q_OBJECT + +public: + VLayersTab( KarbonView* view, QWidget* parent = 0 ); + ~VLayersTab(); + +public slots: + void updatePreviews(); + void updateLayers(); + + void itemClicked( QListViewItem* item, const QPoint&, int col ); + void selectionChangedFromList(); + void selectionChangedFromTool(); + void renameItem( QListViewItem* item, const QPoint&, int col ); + void addLayer(); + void raiseItem(); + void lowerItem(); + void deleteItem(); + void slotCommandExecuted( VCommand* command ); + +private slots: + void slotButtonClicked( int ID ); + void removeDeletedObjectsFromList(); + void updateChildItems( QListViewItem *item ); + void toggleState( VObject *obj, int col ); + +protected: + VLayerListViewItem* listItem( int pos ); + void updateObjects( VObject *object, QListViewItem *item ); + void resetSelection(); + void selectActiveLayer(); + +private: + QListView *m_layersListView; + QHButtonGroup *m_buttonGroup; + KarbonView *m_view; + VDocument *m_document; + QPtrDict<VLayerListViewItem> m_layers; + QPtrDict<VObjectListViewItem> m_objects; +}; // VLayersTab + +/************************************************************************* + * History Tab * + *************************************************************************/ + +class VHistoryItem; + +class VHistoryGroupItem : public QListViewItem +{ + public: + VHistoryGroupItem( VHistoryItem* item, QListView* parent, QListViewItem* after ); + ~VHistoryGroupItem(); + + void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ); + void paintFocus( QPainter*, const QColorGroup&, const QRect& ); + + virtual QString key( int, bool ) const { return m_key; } + virtual int rtti() const { return 1001; } + + private: + QString m_key; +}; // VHistoryGroupItem + +class VHistoryItem : public QListViewItem +{ + public: + VHistoryItem( VCommand* command, QListView* parent, QListViewItem* after ); + VHistoryItem( VCommand* command, VHistoryGroupItem* parent, QListViewItem* after ); + ~VHistoryItem(); + + VCommand* command() { return m_command; } + + void paintCell( QPainter* p, const QColorGroup& cg, int column, int width, int align ); + void paintFocus( QPainter*, const QColorGroup&, const QRect& ); + + virtual QString key( int, bool ) const { return m_key; } + virtual int rtti() const { return 1002; } + + private: + void init(); + + QString m_key; + VCommand* m_command; +}; // VHistoryItem + +class VHistoryTab : public QWidget +{ + Q_OBJECT + + public: + VHistoryTab( KarbonPart* part, QWidget* parent ); + ~VHistoryTab(); + + bool groupingEnabled(); + + public slots: + void historyCleared(); + void commandExecuted( VCommand* command ); + void slotCommandAdded( VCommand* command ); + void removeFirstCommand(); + void removeLastCommand(); + + void commandClicked( int button, QListViewItem* item, const QPoint& point, int col ); + void groupingChanged( int ); + + signals: + void undoCommand( VCommand* command ); + void redoCommand( VCommand* command ); + void undoCommandsTo( VCommand* command ); + void redoCommandsTo( VCommand* command ); + + private: + QListView* m_history; + QListViewItem* m_lastCommand; + QCheckBox* m_groupCommands; + long m_lastCommandIndex; + + KarbonPart* m_part; +}; // VHistoryTab + +#endif + diff --git a/karbon/dockers/vstrokedocker.cc b/karbon/dockers/vstrokedocker.cc new file mode 100644 index 00000000..200c9dc9 --- /dev/null +++ b/karbon/dockers/vstrokedocker.cc @@ -0,0 +1,211 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qhbuttongroup.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwidget.h> +#include <qtooltip.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <KoMainWindow.h> + +#include "KoUnitWidgets.h" + +#include "karbon_part.h" +#include "karbon_view.h" +#include "vstroke.h" +#include "vselection.h" +#include "vstrokecmd.h" + +#include "vstrokedocker.h" + +VStrokeDocker::VStrokeDocker( KarbonPart* part, KarbonView* parent, const char* /*name*/ ) + : QWidget(), m_part ( part ), m_view( parent ) +{ + setCaption( i18n( "Stroke Properties" ) ); + + QPushButton *button; + + QGridLayout *mainLayout = new QGridLayout( this, 4, 2 ); + + QLabel* widthLabel = new QLabel( i18n ( "stroke width", "Width:" ), this ); + mainLayout->addWidget( widthLabel, 0, 0 ); + // set min/max/step and value in points, then set actual unit + m_setLineWidth = new KoUnitDoubleSpinBox( this, 0.0, 1000.0, 0.5, 1.0, KoUnit::U_PT, 2 ); + m_setLineWidth->setUnit( part->unit() ); + QToolTip::add( m_setLineWidth, i18n( "Set line width of actual selection" ) ); + mainLayout->addWidget ( m_setLineWidth, 0, 1 ); + connect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( widthChanged() ) ); + + QLabel* capLabel = new QLabel( i18n ( "Cap:" ), this ); + mainLayout->addWidget( capLabel, 1, 0 ); + m_capGroup = new QHButtonGroup( this ); + m_capGroup->setFrameShape( QFrame::NoFrame ); + m_capGroup->setInsideMargin( 1 ); + m_capGroup->setExclusive( true ); + button = new QPushButton( "", m_capGroup ); + button->setPixmap( SmallIcon( "cap_butt" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Butt cap" ) ); + m_capGroup->insert( button ); + button = new QPushButton( "", m_capGroup ); + button->setPixmap( SmallIcon( "cap_round" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Round cap" ) ); + m_capGroup->insert( button ); + button = new QPushButton( "", m_capGroup ); + button->setPixmap( SmallIcon( "cap_square" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Square cap" ) ); + m_capGroup->insert( button ); + mainLayout->addWidget( m_capGroup, 1, 1 ); + connect( m_capGroup, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + + QLabel* joinLabel = new QLabel( i18n ( "Join:" ), this ); + mainLayout->addWidget( joinLabel, 2, 0 ); + + m_joinGroup = new QHButtonGroup( this ); + m_joinGroup->setFrameShape( QFrame::NoFrame ); + m_joinGroup->setInsideMargin( 1 ); + m_joinGroup->setExclusive( true ); + button = new QPushButton( "", m_joinGroup ); + button->setPixmap( SmallIcon( "join_miter" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Miter join" ) ); + m_joinGroup->insert( button ); + button = new QPushButton( "", m_joinGroup ); + button->setPixmap( SmallIcon( "join_round" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Round join" ) ); + m_joinGroup->insert( button ); + button = new QPushButton( "", m_joinGroup ); + button->setPixmap( SmallIcon( "join_bevel" ) ); + button->setToggleButton( true ); + QToolTip::add( button, i18n( "Bevel join" ) ); + m_joinGroup->insert( button ); + mainLayout->addWidget( m_joinGroup, 2, 1 ); + connect( m_joinGroup, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); + + mainLayout->setRowStretch( 3, 1 ); + mainLayout->setColStretch( 1, 1 ); + mainLayout->activate(); + + updateDocker(); +} + +void VStrokeDocker::updateCanvas() +{ + if( m_part && m_part->document().selection()->objects().count() > 0 ) + m_part->addCommand( new VStrokeCmd( &m_part->document(), &m_stroke ), true ); +} + +void VStrokeDocker::slotCapChanged( int ID ) +{ + switch( ID ) + { + case 1: + m_stroke.setLineCap( VStroke::capRound ); break; + case 2: + m_stroke.setLineCap( VStroke::capSquare ); break; + default: + m_stroke.setLineCap( VStroke::capButt ); + } + updateCanvas(); +} + +void VStrokeDocker::slotJoinChanged( int ID ) +{ + switch( ID ) + { + case 1: + m_stroke.setLineJoin( VStroke::joinRound ); break; + case 2: + m_stroke.setLineJoin( VStroke::joinBevel ); break; + default: + m_stroke.setLineJoin( VStroke::joinMiter ); + } + updateCanvas(); +} + +void VStrokeDocker::updateDocker() +{ + disconnect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( widthChanged() ) ); + disconnect( m_capGroup, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + disconnect( m_joinGroup, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); + + switch( m_stroke.lineCap() ) + { + case VStroke::capRound: + m_capGroup->setButton( 1 ); break; + case VStroke::capSquare: + m_capGroup->setButton( 2 ); break; + default: + m_capGroup->setButton( 0 ); + } + + switch( m_stroke.lineJoin() ) + { + case VStroke::joinRound: + m_joinGroup->setButton( 1 ); break; + case VStroke::joinBevel: + m_joinGroup->setButton( 2 ); break; + default: + m_joinGroup->setButton( 0 ); + } + + m_setLineWidth->changeValue( m_stroke.lineWidth() ); + + connect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( widthChanged() ) ); + connect( m_capGroup, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + connect( m_joinGroup, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); +} + +void VStrokeDocker::widthChanged() +{ + m_stroke.setLineWidth( m_setLineWidth->value() ); + updateCanvas(); +} + +void VStrokeDocker::setStroke( const VStroke &stroke ) +{ + if( &stroke ) + m_stroke = stroke; + else + m_stroke = VStroke(); + updateDocker(); +} + +void VStrokeDocker::setUnit( KoUnit::Unit unit ) +{ + disconnect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( widthChanged() ) ); + disconnect( m_capGroup, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + disconnect( m_joinGroup, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); + + m_setLineWidth->setUnit( unit ); + + connect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( widthChanged() ) ); + connect( m_capGroup, SIGNAL( clicked( int ) ), this, SLOT( slotCapChanged( int ) ) ); + connect( m_joinGroup, SIGNAL( clicked( int ) ), this, SLOT( slotJoinChanged( int ) ) ); +} +#include "vstrokedocker.moc" + diff --git a/karbon/dockers/vstrokedocker.h b/karbon/dockers/vstrokedocker.h new file mode 100644 index 00000000..77d536b9 --- /dev/null +++ b/karbon/dockers/vstrokedocker.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTROKEDOCKER_H__ +#define __VSTROKEDOCKER_H__ + +class QHButtonGroup; +class QWidget; + +class KoUnitDoubleSpinBox; + +class KoMainWindow; +class KarbonView; +class KarbonPart; + +class VStrokeDocker : public QWidget +{ + Q_OBJECT + +public: + VStrokeDocker( KarbonPart* part, KarbonView* parent = 0L, const char* name = 0L ); + +public slots: + virtual void setStroke( const VStroke & ); + virtual void setUnit( KoUnit::Unit unit ); + +private: + QHButtonGroup *m_capGroup; + QHButtonGroup *m_joinGroup; + KarbonPart *m_part; + KarbonView *m_view; + KoUnitDoubleSpinBox *m_setLineWidth; + +private slots: + void slotCapChanged( int ID ); + void slotJoinChanged( int ID ); + void updateCanvas(); + void updateDocker(); + void widthChanged(); + +protected: + VStroke m_stroke; +}; + +#endif + diff --git a/karbon/dockers/vstyledocker.cc b/karbon/dockers/vstyledocker.cc new file mode 100644 index 00000000..9a7ce083 --- /dev/null +++ b/karbon/dockers/vstyledocker.cc @@ -0,0 +1,303 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qlayout.h> +#include <qtabwidget.h> +#include <qsize.h> +#include <qhbuttongroup.h> +#include <qtoolbutton.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <KoMainWindow.h> +#include <KoFilterManager.h> +#include <kfiledialog.h> + +#include "karbon_part.h" +#include "karbon_view.h" +#include "karbon_factory.h" +#include "karbon_resourceserver.h" +#include "karbon_drag.h" +#include "vselection.h" +#include "vlayer.h" +#include "vfill.h" +#include "vfillcmd.h" +#include "vtransformcmd.h" + +#include "vstyledocker.h" + +#include <unistd.h> + +ClipartChooser::ClipartChooser( QSize iconSize, QWidget *parent, const char *name ) + : KoIconChooser( iconSize, parent, name ) +{ + setDragEnabled( true ); +} + +void +ClipartChooser::startDrag() +{ + KoIconChooser::startDrag(); + KarbonDrag* kd = new KarbonDrag( this ); + VObjectList objects; + VClipartIconItem *selectedClipart = (VClipartIconItem *)currentItem(); + double s = kMax( selectedClipart->originalWidth(), selectedClipart->originalHeight() ); + VObject *clipart = selectedClipart->clipart()->clone(); + + QWMatrix mat( s, 0, 0, -s, -( s / 2 ), ( s / 2 ) ); + + VTransformCmd trafo( 0L, mat ); + trafo.visit( *clipart ); + + objects.append( clipart ); + kd->setObjectList( objects ); + kd->dragCopy(); +} + +VStyleDocker::VStyleDocker( KarbonPart* part, KarbonView* parent, const char* /*name*/ ) + : QWidget(), m_part ( part ), m_view( parent ) +{ + setCaption( i18n( "Resources" ) ); + + mTabWidget = new QTabWidget( this ); + + //Pattern + KoPatternChooser *pPatternChooser = new KoPatternChooser( KarbonFactory::rServer()->patterns(), mTabWidget ); + pPatternChooser->setCaption( i18n( "Patterns" ) ); + + connect( pPatternChooser, SIGNAL(selected( KoIconItem * ) ), this, SLOT( slotItemSelected( KoIconItem * ))); + connect( KarbonFactory::rServer(), SIGNAL( patternAdded( KoIconItem * )), pPatternChooser, SLOT( addPattern( KoIconItem * ))); + connect( KarbonFactory::rServer(), SIGNAL( patternRemoved( KoIconItem * )), pPatternChooser, SLOT( removePattern( KoIconItem * ))); + mTabWidget->addTab( pPatternChooser, i18n( "Patterns" ) ); + + //Clipart + ClipartWidget *pClipartWidget = new ClipartWidget( KarbonFactory::rServer()->cliparts(), part, mTabWidget ); + mTabWidget->addTab( pClipartWidget, i18n( "Clipart" ) ); + + QVBoxLayout *mainWidgetLayout = new QVBoxLayout( this, 2 ); + mainWidgetLayout->addWidget( mTabWidget ); + mainWidgetLayout->activate(); + setMinimumHeight( 174 ); + setMinimumWidth( 194 ); +} + +VStyleDocker::~VStyleDocker() +{ +} + +void VStyleDocker::slotItemSelected( KoIconItem *item ) +{ + VPattern *pattern = (VPattern *)item; + if( !pattern ) return; + kdDebug(38000) << "loading pattern : " << pattern->tilename().latin1() << endl; + if( m_part && m_part->document().selection() ) + { + VFill fill; + fill.pattern() = *pattern;//.load( pattern->tilename() ); + //fill.setColor( *m_color ); + fill.setType( VFill::patt ); + m_part->addCommand( new VFillCmd( &m_part->document(), fill ), true ); + } +} + +void +VStyleDocker::mouseReleaseEvent( QMouseEvent * ) +{ +} + +ClipartWidget::ClipartWidget( QPtrList<VClipartIconItem>* clipartItems, KarbonPart *part, QWidget* parent ) + : QWidget( parent ), m_part( part ) +{ + KIconLoader il; + + QVBoxLayout* layout = new QVBoxLayout( this ); + layout->addWidget( m_clipartChooser = new ClipartChooser( QSize( 32, 32 ), this ) ); + layout->addWidget( m_buttonGroup = new QHButtonGroup( this ) ); + QToolButton* m_addClipartButton; + m_buttonGroup->insert( m_addClipartButton = new QToolButton( m_buttonGroup ) ); + m_buttonGroup->insert( m_importClipartButton = new QToolButton( m_buttonGroup ) ); + m_buttonGroup->insert( m_deleteClipartButton = new QToolButton( m_buttonGroup ) ); + m_addClipartButton->setIconSet( SmallIcon( "14_layer_newlayer" ) ); + m_addClipartButton->setTextLabel( i18n( "Add" ) ); + m_importClipartButton->setIconSet( SmallIcon( "fileimport" ) ); + m_importClipartButton->setTextLabel( i18n( "Import" ) ); + m_deleteClipartButton->setIconSet( SmallIcon( "14_layer_deletelayer" ) ); + m_deleteClipartButton->setTextLabel( i18n( "Delete" ) ); + + m_buttonGroup->setInsideMargin( 3 ); + + //setFrameStyle( Box | Sunken ); + layout->setMargin( 3 ); + + connect( m_buttonGroup, SIGNAL( clicked( int ) ), this, SLOT( slotButtonClicked( int ) ) ); + //connect( m_deleteClipartButton, SIGNAL( clicked() ), this, SLOT( deleteClipart() ) ); + connect( m_clipartChooser, SIGNAL( selected( KoIconItem* ) ), this, SLOT( clipartSelected( KoIconItem* ) ) ); + + m_clipartChooser->setAutoDelete( false ); + VClipartIconItem* item = 0L; + + for( item = clipartItems->first(); item; item = clipartItems->next() ) + m_clipartChooser->addItem( item ); + + m_clipartItem = ( clipartItems->first() ) ? clipartItems->first()->clone() : 0; + if( !m_clipartItem ) + m_deleteClipartButton->setEnabled( false ); +} + +ClipartWidget::~ClipartWidget() +{ + delete m_clipartItem; +} + +VClipartIconItem* ClipartWidget::selectedClipart() +{ + return m_clipartItem; +} + +void +ClipartWidget::clipartSelected( KoIconItem* item ) +{ + if( item ) + { + delete m_clipartItem; + VClipartIconItem* clipartItem = ( VClipartIconItem* ) item; + m_deleteClipartButton->setEnabled( clipartItem->canDelete() ); + m_selectedItem = clipartItem; + m_clipartItem = clipartItem->clone(); + } +} + +void +ClipartWidget::addClipart() +{ + VObject* clipart = 0L; + VSelection* selection = m_part->document().selection(); + + if( selection->objects().count() == 1 ) + { + clipart = selection->objects().getFirst()->clone(); + clipart->setParent( 0L ); + } + + if( selection->objects().count() > 1 ) + { + QPtrVector<VObject> objects; + selection->objects().toVector( &objects ); + VGroup* group = new VGroup( 0L ); + + for( unsigned int i = 0; i < objects.count(); i++ ) + { + VObject *obj = objects[ i ]->clone(); + obj->setParent( 0L ); + group->append( obj ); + } + + clipart = group; + } + + if( clipart ) + { + KoRect clipartBox = clipart->boundingBox(); + double scaleFactor = 1. / kMax( clipartBox.width(), clipartBox.height() ); + QWMatrix trMatrix( scaleFactor, 0, 0, scaleFactor, -clipartBox.x() * scaleFactor, -clipartBox.y() * scaleFactor ); + + VTransformCmd trafo( 0L, trMatrix ); + trafo.visit( *clipart ); + + // center the clipart + trMatrix.reset(); + double size = kMax( clipart->boundingBox().width(), clipart->boundingBox().height() ); + trMatrix.translate( ( size - clipart->boundingBox().width() ) / 2, ( size - clipart->boundingBox().height() ) / 2 ); + + trafo.setMatrix( trMatrix ); + trafo.visit( *clipart ); + + // remove Y-mirroring + trMatrix.reset(); + trMatrix.scale( 1, -1 ); + trMatrix.translate( 0, -1 ); + + trafo.setMatrix( trMatrix ); + trafo.visit( *clipart ); + + m_clipartChooser->addItem( KarbonFactory::rServer()->addClipart( clipart, clipartBox.width(), clipartBox.height() ) ); + } + + m_clipartChooser->updateContents(); +} + +void +ClipartWidget::importClipart() +{ + QStringList filter; + filter << "application/x-karbon" << "image/svg+xml" << "image/x-wmf" << "image/x-eps" << "application/postscript"; + KFileDialog *dialog = new KFileDialog( "foo", QString::null, 0L, "Choose Graphic to Add", true); + dialog->setMimeFilter( filter, "application/x-karbon" ); + if( dialog->exec()!=QDialog::Accepted ) + { + delete dialog; + return; + } + QString fname = dialog->selectedFile(); + delete dialog; + if( m_part->nativeFormatMimeType() == dialog->currentMimeFilter().latin1() ) + m_part->mergeNativeFormat( fname ); + else + { + KoFilterManager man( m_part ); + KoFilter::ConversionStatus status; + QString importedFile = man.import( fname, status ); + if( status == KoFilter::OK ) + m_part->mergeNativeFormat( importedFile ); + if( !importedFile.isEmpty() ) + unlink( QFile::encodeName( importedFile ) ); + if( status != KoFilter::OK ) + return; + } + m_part->document().selection()->clear(); + m_part->document().selection()->append( m_part->document().activeLayer()->objects() ); + addClipart(); + m_part->document().selection()->clear(); + m_part->document().removeLayer( m_part->document().activeLayer() ); +} + +void +ClipartWidget::deleteClipart() +{ + VClipartIconItem* clipartItem = m_clipartItem; + KarbonFactory::rServer()->removeClipart( clipartItem ); + m_clipartChooser->removeItem( m_selectedItem ); + m_clipartChooser->updateContents(); +} + +void +ClipartWidget::slotButtonClicked( int id ) +{ + switch( id ) + { + case 0: addClipart(); break; + case 1: importClipart(); break; + case 2: deleteClipart(); + } +} + +#include "vstyledocker.moc" + diff --git a/karbon/dockers/vstyledocker.h b/karbon/dockers/vstyledocker.h new file mode 100644 index 00000000..b1187735 --- /dev/null +++ b/karbon/dockers/vstyledocker.h @@ -0,0 +1,89 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTYLEDOCKER_H__ +#define __VSTYLEDOCKER_H__ + +#include <koIconChooser.h> +#include <qwidget.h> + +class QTabWidget; +class KarbonView; +class KarbonPart; +class QHButtonGroup; +class QToolButton; + +class VClipartIconItem; + +class ClipartChooser : public KoIconChooser +{ +public: + ClipartChooser( QSize iconSize, QWidget *parent = 0L, const char *name = 0L ); + virtual void startDrag(); +}; + +class ClipartWidget : public QWidget +{ + Q_OBJECT + +public: + ClipartWidget( QPtrList<VClipartIconItem>* clipartItems, KarbonPart *part, QWidget* parent = 0L ); + ~ClipartWidget(); + + VClipartIconItem* selectedClipart(); + +public slots: + void addClipart(); + void importClipart(); + void deleteClipart(); + void clipartSelected( KoIconItem* item ); + + void slotButtonClicked( int id ); + +private: + ClipartChooser* m_clipartChooser; + QHButtonGroup* m_buttonGroup; + QToolButton* m_importClipartButton; + QToolButton* m_deleteClipartButton; + KarbonPart* m_part; + VClipartIconItem* m_clipartItem; + VClipartIconItem* m_selectedItem; +}; + +class VStyleDocker : public QWidget +{ + Q_OBJECT + +public: + VStyleDocker( KarbonPart* part, KarbonView* parent = 0L, const char* name = 0L ); + virtual ~VStyleDocker(); + +public slots: + void slotItemSelected( KoIconItem * ); + +private: + virtual void mouseReleaseEvent( QMouseEvent *e ); + QTabWidget *mTabWidget; + KarbonPart *m_part; + KarbonView *m_view; +}; + +#endif + diff --git a/karbon/dockers/vtransformdocker.cc b/karbon/dockers/vtransformdocker.cc new file mode 100644 index 00000000..56b07161 --- /dev/null +++ b/karbon/dockers/vtransformdocker.cc @@ -0,0 +1,265 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qlayout.h> +#include <qwidget.h> +#include <qwmatrix.h> +#include <qtooltip.h> + +#include <klocale.h> +#include <KoMainWindow.h> +#include <KoRect.h> +#include <KoUnitWidgets.h> + +#include "karbon_part.h" +#include "karbon_view.h" + +#include "vselection.h" +#include "vtransformcmd.h" + +#include "vtransformdocker.h" + +VTransformDocker::VTransformDocker( KarbonPart* part, KarbonView* parent, const char* /*name*/ ) + : QWidget(), m_part ( part ), m_view( parent ) +{ + setCaption( i18n( "Transform" ) ); + + QGridLayout *mainLayout = new QGridLayout( this, 5, 5 ); + + //X: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* xLabel = new QLabel( i18n ( "X:" ), this ); + mainLayout->addWidget( xLabel, 0, 0 ); + m_x = new KoUnitDoubleSpinBox( this, -5000.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_x, 0, 1 ); + QToolTip::add( m_x, i18n("Set x-position of actual selection") ); + + //Y: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* yLabel = new QLabel( i18n ( "Y:" ), this ); + mainLayout->addWidget( yLabel, 0, 2 ); + m_y = new KoUnitDoubleSpinBox( this, -5000.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_y, 0, 3 ); + QToolTip::add( m_y, i18n("Set y-position of actual selection") ); + + //Width: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* wLabel = new QLabel( i18n ( "W:" ), this ); + mainLayout->addWidget( wLabel, 1, 0 ); + m_width = new KoUnitDoubleSpinBox( this, 0.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_width, 1, 1 ); + QToolTip::add( m_width, i18n("Set width of actual selection") ); + + //Height: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* hLabel = new QLabel( i18n ( "H:" ), this ); + mainLayout->addWidget( hLabel, 1, 2 ); + m_height = new KoUnitDoubleSpinBox( this, 0.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_height, 1, 3 ); + QToolTip::add( m_height, i18n("Set height of actual selection") ); + + //TODO: Add Rotation, Shear + //ROTATE: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* rLabel = new QLabel( i18n ( "R:" ), this ); + mainLayout->addWidget( rLabel, 3, 0 ); + m_rotate = new KDoubleSpinBox( -360.0, 360.0, 1.0, 10.0, 1, this ); + mainLayout->addWidget( m_rotate, 3, 1 ); + QToolTip::add( m_rotate, i18n("Rotate actual selection") ); + + //X-Shear: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* sxLabel = new QLabel( i18n ( "SX:" ), this ); + mainLayout->addWidget( sxLabel, 2, 0 ); + m_shearX = new KoUnitDoubleSpinBox( this, -5000.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_shearX, 2, 1 ); + QToolTip::add( m_shearX, i18n("Shear actual selection in x-direction") ); + + //Y-Shear: (TODO: Set 5000 limit to real Karbon14 limit) + QLabel* syLabel = new QLabel( i18n ( "SY:" ), this ); + mainLayout->addWidget( syLabel, 2, 2 ); + m_shearY = new KoUnitDoubleSpinBox( this, -5000.0, 5000.0, 1.0, 10.0, m_part->unit(), 1 ); + mainLayout->addWidget( m_shearY, 2, 3 ); + QToolTip::add( m_shearY, i18n("Shear actual selection in y-direction") ); + + mainLayout->setRowStretch( 4, 1 ); + mainLayout->setColStretch( 1, 1 ); + mainLayout->setColStretch( 3, 1 ); + + update(); +} + +void +VTransformDocker::enableSignals( bool enable ) +{ + if( enable ) + { + connect( m_x, SIGNAL( valueChanged( double ) ), this, SLOT( translate() ) ); + connect( m_y, SIGNAL( valueChanged( double ) ), this, SLOT( translate() ) ); + connect( m_width, SIGNAL( valueChanged( double ) ), this, SLOT( scale() ) ); + connect( m_height, SIGNAL( valueChanged( double ) ), this, SLOT( scale() ) ); + connect( m_shearX, SIGNAL( valueChanged( double ) ), this, SLOT( shearX() ) ); + connect( m_shearY, SIGNAL( valueChanged( double ) ), this, SLOT( shearY() ) ); + connect( m_rotate, SIGNAL( valueChanged( double ) ), this, SLOT( rotate() ) ); + } + else + { + disconnect( m_x, SIGNAL( valueChanged( double ) ), this, SLOT( translate() ) ); + disconnect( m_y, SIGNAL( valueChanged( double ) ), this, SLOT( translate() ) ); + disconnect( m_width, SIGNAL( valueChanged( double ) ), this, SLOT( scale() ) ); + disconnect( m_height, SIGNAL( valueChanged( double ) ), this, SLOT( scale() ) ); + disconnect( m_shearX, SIGNAL( valueChanged( double ) ), this, SLOT( shearX() ) ); + disconnect( m_shearY, SIGNAL( valueChanged( double ) ), this, SLOT( shearY() ) ); + disconnect( m_rotate, SIGNAL( valueChanged( double ) ), this, SLOT( rotate() ) ); + } +} + +void +VTransformDocker::update() +{ + enableSignals( false ); + + int objcount = m_view->part()->document().selection()->objects().count(); + if ( objcount>0 ) + { + setEnabled( true ); + KoRect rect = m_view->part()->document().selection()->boundingBox(); + + m_x->changeValue( rect.x() ); + m_y->changeValue( rect.y() ); + m_width->changeValue( rect.width() ); + m_height->changeValue( rect.height() ); + } + else + { + m_x->changeValue(0.0); + m_y->changeValue(0.0); + m_width->changeValue(0.0); + m_height->changeValue(0.0); + setEnabled( false ); + } + + m_shearX->changeValue(0.0); + m_shearY->changeValue(0.0); + m_rotate->setValue(0.0); + + enableSignals( true ); +} + +void +VTransformDocker::translate() +{ + //FIXME: Needs an appropriate transform command which takes absolute values of object size + double newX = m_x->value(); + double newY = m_y->value(); + + KoRect rect = m_view->part()->document().selection()->boundingBox(); + + if( rect.x() != newX || rect.y() != newY ) + { + VTranslateCmd *cmd = new VTranslateCmd( &m_view->part()->document(), newX-rect.x(), newY-rect.y(), false ); + m_view->part()->addCommand( cmd ); + } + m_part->repaintAllViews( true ); +} + +void +VTransformDocker::scale() +{ + //FIXME: Needs an appropriate transform command which takes absolute values of object size + double newW = m_width->value(); + double newH = m_height->value(); + + KoRect rect = m_view->part()->document().selection()->boundingBox(); + + if( rect.width() != newW || rect.height() != newH ) + { + + VScaleCmd *cmd = new VScaleCmd( &m_view->part()->document(), rect.topLeft(), newW/rect.width(), newH/rect.height(), false ); + m_view->part()->addCommand( cmd ); + } + m_part->repaintAllViews( true ); +} + +void +VTransformDocker::setUnit( KoUnit::Unit unit ) +{ + enableSignals( false ); + + m_x->setUnit( unit ); + m_y->setUnit( unit ); + m_width->setUnit( unit ); + m_height->setUnit( unit ); + m_shearX->setUnit( unit ); + m_shearY->setUnit( unit ); + + enableSignals( true ); +} + +void +VTransformDocker::shearX() +{ + double shear = m_shearX->value(); + + if( shear != 0.0 ) + { + KoRect rect = m_view->part()->document().selection()->boundingBox(); + shear /= double(rect.width()*0.5); + VShearCmd *cmd = new VShearCmd( &m_view->part()->document(), rect.center(), shear, 0 ); + m_view->part()->addCommand( cmd ); + m_part->repaintAllViews( true ); + disconnect( m_shearX, SIGNAL( valueChanged( double ) ), this, SLOT( shearX() ) ); + m_shearX->changeValue(0.0); + connect( m_shearX, SIGNAL( valueChanged( double ) ), this, SLOT( shearX() ) ); + } +} + +void +VTransformDocker::shearY() +{ + double shear = m_shearY->value(); + + if( shear != 0.0 ) + { + KoRect rect = m_view->part()->document().selection()->boundingBox(); + shear /= double(rect.height()*0.5); + VShearCmd *cmd = new VShearCmd( &m_view->part()->document(), rect.center(), 0, shear ); + m_view->part()->addCommand( cmd ); + m_part->repaintAllViews( true ); + disconnect( m_shearY, SIGNAL( valueChanged( double ) ), this, SLOT( shearY() ) ); + m_shearY->changeValue(0.0); + connect( m_shearY, SIGNAL( valueChanged( double ) ), this, SLOT( shearY() ) ); + } +} + +void +VTransformDocker::rotate() +{ + double angle = m_rotate->value(); + + if( angle != 0.0 ) + { + KoPoint center = m_view->part()->document().selection()->boundingBox().center(); + VRotateCmd *cmd = new VRotateCmd( &m_view->part()->document(), center, angle ); + m_view->part()->addCommand( cmd ); + m_part->repaintAllViews( true ); + disconnect( m_rotate, SIGNAL( valueChanged( double ) ), this, SLOT( rotate() ) ); + m_rotate->setValue(0.0); + connect( m_rotate, SIGNAL( valueChanged( double ) ), this, SLOT( rotate() ) ); + } +} + +#include "vtransformdocker.moc" + diff --git a/karbon/dockers/vtransformdocker.h b/karbon/dockers/vtransformdocker.h new file mode 100644 index 00000000..3ba161d4 --- /dev/null +++ b/karbon/dockers/vtransformdocker.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTRANSFORMDOCKER_H__ +#define __VTRANSFORMDOCKER_H__ + +class KarbonPart; +class KarbonView; +class KoUnitDoubleSpinBox; + +class VTransformDocker : public QWidget +{ + Q_OBJECT + +public: + VTransformDocker( KarbonPart* part, KarbonView* parent = 0L, const char* name = 0L ); + +public slots: + void update(); + virtual void setUnit( KoUnit::Unit unit ); + +private slots: + void translate(); + void scale(); + void enableSignals( bool enable ); + void shearX(); + void shearY(); + void rotate(); + +private: + KarbonPart *m_part; + KarbonView *m_view; + KoUnitDoubleSpinBox *m_x; + KoUnitDoubleSpinBox *m_y; + KoUnitDoubleSpinBox *m_width; + KoUnitDoubleSpinBox *m_height; + KDoubleSpinBox *m_rotate; + KoUnitDoubleSpinBox *m_shearX; + KoUnitDoubleSpinBox *m_shearY; +}; + +#endif + diff --git a/karbon/karbon.dtd b/karbon/karbon.dtd new file mode 100644 index 00000000..9a277f84 --- /dev/null +++ b/karbon/karbon.dtd @@ -0,0 +1,97 @@ +<!-- Document Type Definition for the Karbon14 Markup Language + the file format for Karbon. + version = 0.1 status = draft date = 11/Mar/2002 + syntax = XML author = dirk.schoenberger@sz-online.de --> +<!-- ============================================================= --> + +<!-- ============================================================= --> + +<!ELEMENT DOC (LAYER*) > +<!ATTLIST DOC editor CDATA "Karbon14" + mime CDATA "application/x-karbon" + syntaxVersion CDATA #IMPLIED +> + +<!-- + The document is grouped by layers. +--> + +<!ELEMENT LAYER (COMPOSITE*) > +<!ATTLIST LAYER name CDATA #IMPLIED + visible ( 0 | 1 ) "1" +> + +<!-- + A composite path. +--> + +<!ELEMENT COMPOSITE (STROKE? FILL? PATH+) > +<!ATTLIST COMPOSITE fillrule ( 0 | 1 ) "0" +> + +<!-- + Stroke mode and color. +--> + +<!ELEMENT STROKE (COLOR) > +<!ATTLIST STROKE lineWidth CDATA #IMPLIED + lineJoin ( 0 | 1 | 2 ) "0" + lineCap ( 0 | 1 | 2 ) "0" + miterLimit CDATA #IMPLIED +> + +<!-- + Fill mode and color. +--> + +<!ELEMENT FILL (COLOR) > + +<!-- + Color data. +--> + +<!ELEMENT COLOR EMPTY > +<!ATTLIST COLOR colorSpace ( 0 | 1 | 2 ) "0" + v1 CDATA #IMPLIED + v2 CDATA #IMPLIED + v3 CDATA #IMPLIED + v4 CDATA #IMPLIED +> + +<!-- + A path. +--> + +<!ELEMENT PATH MOVE ( LINE | CURVE )+ > +<!ATTLIST PATH isClosed ( 0 | 1 ) "1" +> + +<!-- + Path segment data. +--> + +<!ELEMENT MOVE EMPTY > +<!ATTLIST MOVE x CDATA #IMPLIED + y CDATA #IMPLIED +> + +<!ELEMENT LINE EMPTY > +<!ATTLIST LINE x CDATA #IMPLIED + y CDATA #IMPLIED +> + +<!ELEMENT CURVE EMPTY > +<!ATTLIST CURVE ctrlPointFixing ( 0 | 1 | 2 ) "0" + x1 CDATA #IMPLIED + y1 CDATA #IMPLIED + x2 CDATA #IMPLIED + y2 CDATA #IMPLIED + x3 CDATA #IMPLIED + y3 CDATA #IMPLIED +> + +<!-- ============================================================= --> +<!-- + End of DTD for Karbon +--> + diff --git a/karbon/karbon_aboutdata.h b/karbon/karbon_aboutdata.h new file mode 100644 index 00000000..8d8e5217 --- /dev/null +++ b/karbon/karbon_aboutdata.h @@ -0,0 +1,79 @@ +#ifndef KARBON_ABOUTDATA_H +#define KARBON_ABOUTDATA_H + +#include <kaboutdata.h> +#include <klocale.h> +#include <config.h> + +static const char* description=I18N_NOOP( "A Vector Graphics Drawing Application." ); +static const char* version=VERSION; + +// This is all implemented here so that the executable and the part can share it +// without sharing an object file. +KAboutData * newKarbonAboutData() +{ + KAboutData * aboutData = new KAboutData( + "karbon", + I18N_NOOP( "Karbon14" ), + version, + description, + KAboutData::License_GPL, + I18N_NOOP( "(c) 2001-2006, The Karbon Developers" ), + I18N_NOOP( "You are invited to participate in any way." ), + "http://www.koffice.org/karbon/"); + aboutData->addAuthor( + "Rob Buis", + 0, + "buis@kde.org", + 0 ); + aboutData->addAuthor( + "Tomislav Lukman", + 0, + "tomislav.lukman@ck.t-com.hr", + 0 ); + aboutData->addAuthor( + "Benoît Vautrin", + 0, + "benoit.vautrin@free.fr", + 0 ); + aboutData->addCredit( + "Jan Hambrecht", + I18N_NOOP( "Bug fixes and improvements" ), + "jaham@gmx.net", + 0 ); + aboutData->addCredit( + "Peter Simonsson", + I18N_NOOP( "Bug fixes and improvements" ), + "psn@linux.se", + 0 ); + aboutData->addCredit( + "Tim Beaulen", + I18N_NOOP( "Bug fixes and improvements" ), + "tbscope@gmail.com", + 0 ); + aboutData->addCredit( + "Boudewijn Rempt", + I18N_NOOP( "Bug fixes and improvements" ), + "boud@valdyas.org", + 0 ); + aboutData->addCredit( + "Pierre Stirnweiss", + I18N_NOOP( "Bug fixes and improvements" ), + "pierre.stirnweiss_kde@gadz.org", + 0 ); + aboutData->addCredit( + "Inge Wallin", + I18N_NOOP( "Bug fixes" ), + "inge@lysator.liu.se", + 0 ); + aboutData->addCredit( + "Alan Horkan", + I18N_NOOP( "Helpfull patches and advice" ), + 0, + 0 ); + // TODO: add the names of some helpful souls + return aboutData; +} + +#endif /* KARBON_ABOUTDATA_H */ + diff --git a/karbon/karbon_drag.cpp b/karbon/karbon_drag.cpp new file mode 100644 index 00000000..c605bb3c --- /dev/null +++ b/karbon/karbon_drag.cpp @@ -0,0 +1,122 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "karbon_drag.h" + +#include <qcstring.h> +#include <qdom.h> +#include <qtextstream.h> + +#include "vdocument.h" + +QCString KarbonDrag::m_encodeFormats[NumEncodeFmts]; +QCString KarbonDrag::m_decodeFormats[NumDecodeFmts]; + +KarbonDrag::KarbonDrag( QWidget *dragSource, const char *name ) + : QDragObject( dragSource, name ) +{ + m_encodeFormats[0] = "application/vnd.kde.karbon"; + m_decodeFormats[0] = "application/vnd.kde.karbon"; +} + +const char * +KarbonDrag::format( int i ) const +{ + if( i < NumEncodeFmts ) { + return m_encodeFormats[i]; + } + + return 0L; +} + +QByteArray +KarbonDrag::encodedData( const char* mimetype ) const +{ + QCString result; + + if( m_encodeFormats[0] == mimetype ) + { + VObjectListIterator itr( m_objects ); + // build a xml fragment containing the selection as karbon xml + QDomDocument doc( "clip" ); + QDomElement elem = doc.createElement( "clip" ); + QTextStream ts( result, IO_WriteOnly ); + + for( ; itr.current() ; ++itr ) + itr.current()->save( elem ); + + ts << elem; + } + + return result; +} + +bool +KarbonDrag::canDecode( QMimeSource* e) +{ + for( int i = 0; i < NumDecodeFmts; i++ ) + { + if( e->provides( m_decodeFormats[i] ) ) + return true; + } + + return false; +} + +bool +KarbonDrag::decode( QMimeSource* e, VObjectList& sl, VDocument& vdoc ) +{ + if( e->provides( m_decodeFormats[0] ) ) + { + QDomDocument doc( "clip" ); + QByteArray data = e->encodedData( m_decodeFormats[0] ); + doc.setContent( QCString( data, data.size()+1 ) ); + QDomElement clip = doc.documentElement(); + // Try to parse the clipboard data + if( clip.tagName() == "clip" ) + { + VGroup grp( &vdoc ); + grp.load( clip ); + VObjectListIterator itr( grp.objects() ); + for( ; itr.current() ; ++itr ) + { + VObject *obj = itr.current()->clone(); + obj->setParent( 0L ); + sl.append( obj ); + } + + return true; + } + } + + return false; +} + +void +KarbonDrag::setObjectList( VObjectList l ) +{ + VObjectListIterator itr( l ); + m_objects.clear(); + + for( ; itr.current() ; ++itr ) + m_objects.append( itr.current()->clone() ); +} + +#include "karbon_drag.moc" + diff --git a/karbon/karbon_drag.h b/karbon/karbon_drag.h new file mode 100644 index 00000000..96a72d32 --- /dev/null +++ b/karbon/karbon_drag.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KARBON_DRAG_H +#define KARBON_DRAG_H + +#include <qdragobject.h> + +#include "vgroup.h" + +class VDocument; + +#define NumEncodeFmts 1 +#define NumDecodeFmts 1 + +class KarbonDrag : public QDragObject +{ + Q_OBJECT +public: + KarbonDrag( QWidget* dragSource = 0, const char* name = 0 ); + const char* format( int i ) const; + QByteArray encodedData( const char* mimetype ) const; + static bool canDecode( QMimeSource * ); + static bool decode( QMimeSource* e, VObjectList& sl, VDocument& vdoc ); + void setObjectList( VObjectList l ); + +private: + static QCString m_encodeFormats[NumEncodeFmts]; + static QCString m_decodeFormats[NumDecodeFmts]; + VObjectList m_objects; +}; + +#endif + diff --git a/karbon/karbon_factory.cc b/karbon/karbon_factory.cc new file mode 100644 index 00000000..d751b295 --- /dev/null +++ b/karbon/karbon_factory.cc @@ -0,0 +1,142 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <kaboutdata.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <ktrader.h> +#include <kparts/componentfactory.h> +#include <kparts/plugin.h> + +#include "karbon_factory.h" +#include "karbon_part.h" +#include "karbon_resourceserver.h" +#include "karbon_aboutdata.h" +#include "karbon_tool_registry.h" + +#include <kdebug.h> + +KarbonResourceServer* KarbonFactory::s_rserver = 0; + +KInstance* KarbonFactory::s_instance = 0L; +KAboutData* KarbonFactory::s_aboutData = 0L; + +KarbonFactory::KarbonFactory( QObject* parent, const char* name ) + : KoFactory( parent, name ) +{ + instance(); + + KarbonToolRegistry::instance(); + + // Load plugins + KTrader::OfferList offers = KTrader::self() -> query(QString::fromLatin1("Karbon/CoreModule"), + QString::fromLatin1("Type == 'Service'")); + + KTrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService<KParts::Plugin> ( service, this, 0, QStringList(), &errCode); + if ( plugin ) + kdDebug() << "found plugin " << service -> property("Name").toString() << "\n"; + } +} + +KarbonFactory::~KarbonFactory() +{ + delete s_instance; + s_instance = 0L; + delete s_aboutData; + s_aboutData = 0L; + delete s_rserver; + s_rserver = 0L; +} + +KParts::Part* +KarbonFactory::createPartObject( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, const char* classname, const QStringList& ) +{ + // If classname is "KoDocument", our host is a koffice application + // otherwise, the host wants us as a simple part, so switch to readonly and + // single view. + bool bWantKoDocument = ( strcmp( classname, "KoDocument" ) == 0 ); + + // parentWidget and widgetName are used by KoDocument for the + // "readonly+singleView" case. + KarbonPart* part = + new KarbonPart( parentWidget, widgetName, parent, name, !bWantKoDocument ); + + if( !bWantKoDocument ) + part->setReadWrite( false ); + + return part; +} + +KAboutData* +KarbonFactory::aboutData() +{ + if( !s_aboutData ) + s_aboutData = newKarbonAboutData(); + return s_aboutData; +} + +KInstance* +KarbonFactory::instance() +{ + if( !s_instance ) + { + s_instance = new KInstance( aboutData() ); + // Add any application-specific resource directories here + + s_instance->dirs()->addResourceType( "kis_brushes", + KStandardDirs::kde_default( "data" ) + "krita/brushes/" ); + + s_instance->dirs()->addResourceType( "kis_pattern", + KStandardDirs::kde_default( "data" ) + "krita/patterns/" ); + + s_instance->dirs()->addResourceType( "karbon_gradient", + KStandardDirs::kde_default( "data" ) + "karbon/gradients/" ); + + s_instance->dirs()->addResourceType( "karbon_clipart", + KStandardDirs::kde_default( "data" ) + "karbon/cliparts/" ); + s_instance->dirs()->addResourceType( "karbon_template", KStandardDirs::kde_default("data") + "karbon/templates/" ); + // Tell the iconloader about share/apps/koffice/icons + s_instance->iconLoader()->addAppDir("koffice"); + } + + return s_instance; +} + +KarbonResourceServer *KarbonFactory::rServer() +{ + if( !s_rserver ) + s_rserver = new KarbonResourceServer; + + return s_rserver; +} + +#include "karbon_factory.moc" + diff --git a/karbon/karbon_factory.h b/karbon/karbon_factory.h new file mode 100644 index 00000000..553a2109 --- /dev/null +++ b/karbon/karbon_factory.h @@ -0,0 +1,55 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBON_FACTORY_H__ +#define __KARBON_FACTORY_H__ + +#include <KoFactory.h> +#include <koffice_export.h> +class KAboutData; +class KInstance; + +class KarbonResourceServer; + + +class KARBONCOMMON_EXPORT KarbonFactory : public KoFactory +{ + Q_OBJECT + +public: + KarbonFactory( QObject* parent = 0, const char* name = 0 ); + ~KarbonFactory(); + + virtual KParts::Part* createPartObject( QWidget *parentWidget = 0, + const char* widgetName = 0L, QObject* parent = 0L, const char* name = 0L, + const char* classname = "KoDocument", const QStringList& args = QStringList() ); + + static KInstance* instance(); + static KAboutData* aboutData(); + + static KarbonResourceServer *rServer(); + +private: + static KInstance* s_instance; + static KAboutData* s_aboutData; + static KarbonResourceServer* s_rserver; +}; + +#endif + diff --git a/karbon/karbon_factory_init.cc b/karbon/karbon_factory_init.cc new file mode 100644 index 00000000..76315b5e --- /dev/null +++ b/karbon/karbon_factory_init.cc @@ -0,0 +1,23 @@ +/* This file is part of the KDE project + Copyright (C) 2005 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "karbon_factory.h" + +K_EXPORT_COMPONENT_FACTORY( libkarbonpart, KarbonFactory() ) + diff --git a/karbon/karbon_grid_data.cpp b/karbon/karbon_grid_data.cpp new file mode 100644 index 00000000..f1e45ce1 --- /dev/null +++ b/karbon/karbon_grid_data.cpp @@ -0,0 +1,59 @@ +/* + * Karbon - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "karbon_grid_data.h" +#include <qdom.h> + +KarbonGridData::KarbonGridData() +{ + color = QColor( 228, 228, 228 ); + freq = KoSize( 20, 20 ); + snap = KoSize( 20, 20 ); + isSnap = false; + isShow = false; +} + +KarbonGridData::~KarbonGridData() +{ +} + +void KarbonGridData::save(QDomElement& /*element*/, const QString& /*name*/) +{ +/* Karbon::saveSize(element, name + "Freg", freq); + Karbon::saveSize(element, name + "Snap", snap); + XmlWriteColor(element, name + "Color", color); + element.setAttribute(name + "IsSnap", (int)isSnap); + element.setAttribute(name + "IsShow", (int)isShow);*/ +} + +void KarbonGridData::load(const QDomElement& /*element*/, const QString& /*name*/) +{ +/* KoSize sdef; + sdef = KoSize(10.0, 10.0); + freq = Karbon::loadSize(element, name + "Freg", sdef); + snap = Karbon::loadSize(element, name + "Snap", sdef); + + QColor def(QColor(228, 228, 228)); + color = XmlReadColor(element, name + "Color", def); + + isSnap = (bool)element.attribute(name + "IsSnap", "1").toInt(); + isShow = (bool)element.attribute(name + "IsShow", "1").toInt();*/ +} + diff --git a/karbon/karbon_grid_data.h b/karbon/karbon_grid_data.h new file mode 100644 index 00000000..4d25bb8a --- /dev/null +++ b/karbon/karbon_grid_data.h @@ -0,0 +1,44 @@ +/* + * Kivio - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KARBON_GRID_DATA_H +#define KARBON_GRID_DATA_H + +#include <KoSize.h> +#include <qcolor.h> + +class QDomElement; + +class KarbonGridData +{ +public: + KarbonGridData(); + ~KarbonGridData(); + + void save(QDomElement&, const QString&); + void load(const QDomElement&, const QString&); + + KoSize freq; + KoSize snap; + QColor color; + bool isSnap; + bool isShow; +}; + +#endif diff --git a/karbon/karbon_part.cc b/karbon/karbon_part.cc new file mode 100644 index 00000000..deab6739 --- /dev/null +++ b/karbon/karbon_part.cc @@ -0,0 +1,679 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qdom.h> +#include <qfileinfo.h> +#include <qpainter.h> +#include <qpaintdevicemetrics.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <ktempfile.h> +#include <KoTemplateChooseDia.h> +#include <KoStoreDevice.h> +#include <KoOasisStyles.h> +#include <KoOasisLoadingContext.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <KoDom.h> +#include <KoOasisSettings.h> +#include <KoMainWindow.h> + +#include "karbon_factory.h" +#include "karbon_part.h" +#include "karbon_part_iface.h" +#include "karbon_view.h" +#include "vcommand.h" +#include "vglobal.h" +#include "vpainter.h" +#include "vpainterfactory.h" +#include "vselection.h" +#include "vcanvas.h" +#include "vlayer.h" +#include "vdocumentdocker.h" +#include "vtoolcontroller.h" +#include "KoApplication.h" +#include "vtool.h" +#include "commands/vtransformcmd.h" + +// Make sure an appropriate DTD is available in www/koffice/DTD if changing this value +// static const char * CURRENT_DTD_VERSION = "1.2"; + +KarbonPart::KarbonPart( QWidget* parentWidget, const char* widgetName, + QObject* parent, const char* name, bool singleViewMode ) + : KoDocument( parentWidget, widgetName, parent, name, singleViewMode ) +{ + setInstance( KarbonFactory::instance(), false ); + setTemplateType( "karbon_template" ); + m_bShowStatusBar = true; + dcop = 0L; + + m_commandHistory = new VCommandHistory( this ); + connect( m_commandHistory, SIGNAL( documentRestored() ), this, SLOT( slotDocumentRestored() ) ); + connect( m_commandHistory, SIGNAL( commandExecuted( VCommand * ) ), this, SLOT( slotCommandExecuted( VCommand * ) ) ); + + initConfig(); + + m_merge = false; + + m_maxRecentFiles = 10; + + //if( name ) + dcopObject(); + + // set as default paper + m_pageLayout.format = KoPageFormat::defaultFormat(); + m_pageLayout.orientation = PG_PORTRAIT; + m_pageLayout.ptWidth = MM_TO_POINT( KoPageFormat::width( m_pageLayout.format, m_pageLayout.orientation ) ); + m_pageLayout.ptHeight = MM_TO_POINT( KoPageFormat::height( m_pageLayout.format, m_pageLayout.orientation ) ); + m_doc.setWidth( m_pageLayout.ptWidth ); + m_doc.setHeight( m_pageLayout.ptHeight ); + // enable selection drawing + m_doc.selection()->showHandle(); + m_doc.selection()->setSelectObjects(); + m_doc.selection()->setState( VObject::selected ); + m_doc.selection()->selectNodes(); +} + +KarbonPart::~KarbonPart() +{ + // delete the command-history: + delete m_commandHistory; + delete dcop; +} + +DCOPObject* KarbonPart::dcopObject() +{ + if( !dcop ) + dcop = new KarbonPartIface( this ); + + return dcop; +} + +void +KarbonPart::setPageLayout( KoPageLayout& layout, KoUnit::Unit _unit ) +{ + m_pageLayout = layout; + m_doc.setUnit( _unit ); + m_doc.setWidth( m_pageLayout.ptWidth ); + m_doc.setHeight( m_pageLayout.ptHeight ); +} + +bool +KarbonPart::initDoc(InitDocFlags flags, QWidget* parentWidget) +{ + if (flags==KoDocument::InitDocEmpty) + { + return true; + } + QString file; + KoTemplateChooseDia::ReturnType result; + + KoTemplateChooseDia::DialogType dlgtype; + if (flags != KoDocument::InitDocFileNew) + dlgtype = KoTemplateChooseDia::Everything; + else + dlgtype = KoTemplateChooseDia::OnlyTemplates; + + result = KoTemplateChooseDia::choose( KarbonFactory::instance(), file, dlgtype, "karbon_template", parentWidget ); + + if( result == KoTemplateChooseDia::Template ) + { + resetURL(); + bool ok = loadNativeFormat( file ); + if ( !ok ) + showLoadingErrorDialog(); + setEmpty(); + return ok; + } + else if( result == KoTemplateChooseDia::Empty ) + { + return true; + } + else if( result == KoTemplateChooseDia::File ) + { + KURL url( file ); + return openURL( url ); + } + + return false; +} + +KoView* +KarbonPart::createViewInstance( QWidget* parent, const char* name ) +{ + KarbonView *result = new KarbonView( this, parent, name ); + return result; +} + +void +KarbonPart::removeView( KoView *view ) +{ + kdDebug(38000) << "KarbonPart::removeView" << endl; + KoDocument::removeView( view ); +} + +double getAttribute(QDomElement &element, const char *attributeName, double defaultValue) +{ + QString value; + if ( ( value = element.attribute( attributeName ) ) != QString::null ) + return value.toDouble(); + else + return defaultValue; +} + +int getAttribute(QDomElement &element, const char *attributeName, int defaultValue) +{ + QString value; + if ( ( value = element.attribute( attributeName ) ) != QString::null ) + return value.toInt(); + else + return defaultValue; +} + +bool +KarbonPart::loadXML( QIODevice*, const QDomDocument& document ) +{ + bool success = false; + + QDomElement doc = document.documentElement(); + + if( m_merge ) + { + m_doc.loadDocumentContent( doc ); + return true; + } + + success = m_doc.loadXML( doc ); + + //m_pageLayout = KoPageLayout::standardLayout(); + + // <PAPER> + QDomElement paper = doc.namedItem( "PAPER" ).toElement(); + if ( !paper.isNull() ) + { + m_pageLayout.format = static_cast<KoFormat>( getAttribute( paper, "format", 0 ) ); + m_pageLayout.orientation = static_cast<KoOrientation>( getAttribute( paper, "orientation", 0 ) ); + + if( m_pageLayout.format == PG_CUSTOM ) + { + m_pageLayout.ptWidth = m_doc.width(); + m_pageLayout.ptHeight = m_doc.height(); + } + else + { + m_pageLayout.ptWidth = getAttribute( paper, "width", 0.0 ); + m_pageLayout.ptHeight = getAttribute( paper, "height", 0.0 ); + } + } + else + { + m_pageLayout.ptWidth = getAttribute( doc, "width", 595.277); + m_pageLayout.ptHeight = getAttribute( doc, "height", 841.891 ); + } + + kdDebug() << " ptWidth=" << m_pageLayout.ptWidth << endl; + kdDebug() << " ptHeight=" << m_pageLayout.ptHeight << endl; + QDomElement borders = paper.namedItem( "PAPERBORDERS" ).toElement(); + if( !borders.isNull() ) + { + if( borders.hasAttribute( "ptLeft" ) ) + m_pageLayout.ptLeft = borders.attribute( "ptLeft" ).toDouble(); + if( borders.hasAttribute( "ptTop" ) ) + m_pageLayout.ptTop = borders.attribute( "ptTop" ).toDouble(); + if( borders.hasAttribute( "ptRight" ) ) + m_pageLayout.ptRight = borders.attribute( "ptRight" ).toDouble(); + if( borders.hasAttribute( "ptBottom" ) ) + m_pageLayout.ptBottom = borders.attribute( "ptBottom" ).toDouble(); + } + + setUnit( m_doc.unit() ); + + return success; +} + +QDomDocument +KarbonPart::saveXML() +{ + QDomDocument doc = m_doc.saveXML(); + QDomElement me = doc.documentElement(); + QDomElement paper = doc.createElement( "PAPER" ); + me.appendChild( paper ); + paper.setAttribute( "format", static_cast<int>( m_pageLayout.format ) ); + paper.setAttribute( "pages", pageCount() ); + paper.setAttribute( "width", m_pageLayout.ptWidth ); + paper.setAttribute( "height", m_pageLayout.ptHeight ); + paper.setAttribute( "orientation", static_cast<int>( m_pageLayout.orientation ) ); + + QDomElement paperBorders = doc.createElement( "PAPERBORDERS" ); + paperBorders.setAttribute( "ptLeft", m_pageLayout.ptLeft ); + paperBorders.setAttribute( "ptTop", m_pageLayout.ptTop ); + paperBorders.setAttribute( "ptRight", m_pageLayout.ptRight ); + paperBorders.setAttribute( "ptBottom", m_pageLayout.ptBottom ); + paper.appendChild(paperBorders); + + return doc; +} + +bool +KarbonPart::loadOasis( const QDomDocument &doc, KoOasisStyles &styles, const QDomDocument &settings, KoStore *store ) +{ + kdDebug(38000) << "Start loading OASIS document..." << doc.toString() << endl; + + QDomElement contents = doc.documentElement(); + kdDebug(38000) << "Start loading OASIS document..." << contents.text() << endl; + kdDebug(38000) << "Start loading OASIS contents..." << contents.lastChild().localName() << endl; + kdDebug(38000) << "Start loading OASIS contents..." << contents.lastChild().namespaceURI() << endl; + kdDebug(38000) << "Start loading OASIS contents..." << contents.lastChild().isElement() << endl; + QDomElement body( KoDom::namedItemNS( contents, KoXmlNS::office, "body" ) ); + kdDebug(38000) << "Start loading OASIS document..." << body.text() << endl; + if( body.isNull() ) + { + kdDebug(38000) << "No office:body found!" << endl; + setErrorMessage( i18n( "Invalid OASIS document. No office:body tag found." ) ); + return false; + } + + body = KoDom::namedItemNS( body, KoXmlNS::office, "drawing"); + if(body.isNull()) + { + kdDebug(38000) << "No office:drawing found!" << endl; + setErrorMessage( i18n( "Invalid OASIS document. No office:drawing tag found." ) ); + return false; + } + + QDomElement page( KoDom::namedItemNS( body, KoXmlNS::draw, "page" ) ); + if(page.isNull()) + { + kdDebug(38000) << "No office:drawing found!" << endl; + setErrorMessage( i18n( "Invalid OASIS document. No draw:page tag found." ) ); + return false; + } + + QString masterPageName = "Standard"; // use default layout as fallback + QDomElement *master = styles.masterPages()[ masterPageName ]; + if ( !master ) //last test... + master = styles.masterPages()[ "Default" ]; + // last resort, use the first found master page style + if ( ! master ) + { + QDictIterator<QDomElement> it( styles.masterPages() ); + master = it.current(); + } + Q_ASSERT( master ); + const QDomElement *style = master ? styles.findStyle( master->attributeNS( KoXmlNS::style, "page-layout-name", QString::null ) ) : 0; + if( style ) + { + m_pageLayout.loadOasis( *style ); + m_doc.setWidth( m_pageLayout.ptWidth ); + m_doc.setHeight( m_pageLayout.ptHeight ); + } + else + return false; + + KoOasisLoadingContext context( this, styles, store ); + m_doc.loadOasis( page, context ); + // do y-mirroring here + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -m_doc.height() ); + VTransformCmd trafo( 0L, mat ); + trafo.visit( m_doc ); + + loadOasisSettings( settings ); + + return true; +} + +void +KarbonPart::loadOasisSettings( const QDomDocument&settingsDoc ) +{ + if ( settingsDoc.isNull() ) + return ; // not an error if some file doesn't have settings.xml + KoOasisSettings settings( settingsDoc ); + KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); + if ( !viewSettings.isNull() ) + { + setUnit(KoUnit::unit(viewSettings.parseConfigItemString("unit"))); + // FIXME: add other config here. + } +} + + +bool +KarbonPart::saveOasis( KoStore *store, KoXmlWriter *manifestWriter ) +{ + if( !store->open( "content.xml" ) ) + return false; + + KoStoreDevice storeDev( store ); + KoXmlWriter* docWriter = createOasisXmlWriter( &storeDev, "office:document-content" ); + KoGenStyles mainStyles; + + KoGenStyle pageLayout = m_pageLayout.saveOasis(); + QString layoutName = mainStyles.lookup( pageLayout, "PL" ); + KoGenStyle masterPage( KoGenStyle::STYLE_MASTER ); + masterPage.addAttribute( "style:page-layout-name", layoutName ); + mainStyles.lookup( masterPage, "Default", KoGenStyles::DontForceNumbering ); + + KTempFile contentTmpFile; + contentTmpFile.setAutoDelete( true ); + QFile* tmpFile = contentTmpFile.file(); + KoXmlWriter contentTmpWriter( tmpFile, 1 ); + + contentTmpWriter.startElement( "office:body" ); + contentTmpWriter.startElement( "office:drawing" ); + + m_doc.saveOasis( store, &contentTmpWriter, mainStyles ); // Save contents + + contentTmpWriter.endElement(); // office:drawing + contentTmpWriter.endElement(); // office:body + + docWriter->startElement( "office:automatic-styles" ); + + QValueList<KoGenStyles::NamedStyle> styles = mainStyles.styles( VDocument::STYLE_GRAPHICAUTO ); + QValueList<KoGenStyles::NamedStyle>::const_iterator it = styles.begin(); + for( ; it != styles.end() ; ++it ) + (*it).style->writeStyle( docWriter, mainStyles, "style:style", (*it).name , "style:graphic-properties" ); + + docWriter->endElement(); // office:automatic-styles + + // And now we can copy over the contents from the tempfile to the real one + tmpFile->close(); + docWriter->addCompleteElement( tmpFile ); + contentTmpFile.close(); + + docWriter->endElement(); // Root element + docWriter->endDocument(); + delete docWriter; + + if( !store->close() ) + return false; + + manifestWriter->addManifestEntry( "content.xml", "text/xml" ); + + if( !store->open( "styles.xml" ) ) + return false; + + KoXmlWriter* styleWriter = createOasisXmlWriter( &storeDev, "office:document-styles" ); + + styleWriter->startElement( "office:styles" ); + + styles = mainStyles.styles( VDocument::STYLE_LINEAR_GRADIENT ); + it = styles.begin(); + for( ; it != styles.end() ; ++it ) + (*it).style->writeStyle( styleWriter, mainStyles, "svg:linearGradient", (*it).name, 0, true, true /*add draw:name*/); + + styles = mainStyles.styles( VDocument::STYLE_RADIAL_GRADIENT ); + it = styles.begin(); + for( ; it != styles.end() ; ++it ) + (*it).style->writeStyle( styleWriter, mainStyles, "svg:radialGradient", (*it).name, 0, true, true /*add draw:name*/); + + styleWriter->endElement(); // office:styles + + styleWriter->startElement( "office:automatic-styles" ); + + QValueList<KoGenStyles::NamedStyle> styleList = mainStyles.styles( KoGenStyle::STYLE_PAGELAYOUT ); + it = styleList.begin(); + + for( ; it != styleList.end(); ++it ) + (*it).style->writeStyle( styleWriter, mainStyles, "style:page-layout", (*it).name, "style:page-layout-properties" ); + + styleWriter->endElement(); // office:automatic-styles + + styles = mainStyles.styles( KoGenStyle::STYLE_MASTER ); + it = styles.begin(); + styleWriter->startElement("office:master-styles"); + + for( ; it != styles.end(); ++it) + (*it).style->writeStyle( styleWriter, mainStyles, "style:master-page", (*it).name, ""); + + styleWriter->endElement(); // office:master-styles + + styleWriter->endElement(); // Root element + styleWriter->endDocument(); + delete styleWriter; + + if( !store->close() ) + return false; + + manifestWriter->addManifestEntry( "styles.xml", "text/xml" ); + + + if(!store->open("settings.xml")) + return false; + + + KoXmlWriter& settingsWriter = *createOasisXmlWriter(&storeDev, "office:document-settings"); + settingsWriter.startElement("office:settings"); + settingsWriter.startElement("config:config-item-set"); + settingsWriter.addAttribute("config:name", "view-settings"); + + KoUnit::saveOasis(&settingsWriter, unit()); + saveOasisSettings( settingsWriter ); + + settingsWriter.endElement(); // config:config-item-set + settingsWriter.endElement(); // office:settings + settingsWriter.endElement(); // Root element + settingsWriter.endDocument(); + delete &settingsWriter; + + + if(!store->close()) + return false; + + manifestWriter->addManifestEntry("settings.xml", "text/xml"); + + setModified( false ); + return true; +} + +void +KarbonPart::saveOasisSettings( KoXmlWriter &/*settingsWriter*/ ) +{ + //todo +} + +void +KarbonPart::insertObject( VObject* object ) +{ + // don't repaint here explicitly. some commands might want to insert many + // objects. + m_doc.append( object ); + setModified( true ); +} + +void +KarbonPart::addCommand( VCommand* cmd, bool repaint ) +{ + m_commandHistory->addCommand( cmd ); + setModified( true ); + + if( repaint ) + repaintAllViews(); +} + +void +KarbonPart::slotDocumentRestored() +{ + setModified( false ); +} + +void +KarbonPart::slotCommandExecuted( VCommand *command ) +{ + setModified( true ); +} + +void +KarbonPart::clearHistory() +{ + m_commandHistory->clear(); +} + +void +KarbonPart::repaintAllViews( bool repaint ) +{ + QPtrListIterator<KoView> itr( views() ); + + for( ; itr.current() ; ++itr ) + static_cast<KarbonView*>( itr.current() )->canvasWidget()->repaintAll( repaint ); +} + +void +KarbonPart::repaintAllViews( const KoRect &rect ) +{ + QPtrListIterator<KoView> itr( views() ); + + for( ; itr.current() ; ++itr ) + static_cast<KarbonView*>( itr.current() )->canvasWidget()->repaintAll( rect ); +} + +void +KarbonPart::paintContent( QPainter& painter, const QRect& rect, + bool /*transparent*/, double /*zoomX*/, double /*zoomY*/ ) +{ + kdDebug(38000) << "**** part->paintContent()" << endl; + + KoRect r = KoRect::fromQRect( rect ); + double zoomFactorX = double( r.width() ) / double( document().width() ); + double zoomFactorY = double( r.height() ) / double( document().height() ); + double zoomFactor = kMin( zoomFactorX, zoomFactorY ); + + painter.eraseRect( rect ); + VPainterFactory *painterFactory = new VPainterFactory; + //QPaintDeviceMetrics metrics( painter.device() ); + painterFactory->setPainter( painter.device(), rect.width(), rect.height() ); + VPainter *p = painterFactory->painter(); + //VPainter *p = new VKoPainter( painter.device() ); + p->begin(); + p->setZoomFactor( zoomFactor ); + kdDebug(38000) << "painter.worldMatrix().dx() : " << painter.worldMatrix().dx() << endl; + kdDebug(38000) << "painter.worldMatrix().dy() : " << painter.worldMatrix().dy() << endl; + kdDebug(38000) << "rect.x() : "<< rect.x() << endl; + kdDebug(38000) << "rect.y() : "<< rect.y() << endl; + kdDebug(38000) << "rect.width() : "<< rect.width() << endl; + kdDebug(38000) << "rect.height() : "<< rect.height() << endl; + r = document().boundingBox(); + QWMatrix mat = painter.worldMatrix(); + mat.scale( 1, -1 ); + mat.translate( 0, -r.height() * zoomFactor ); + p->setWorldMatrix( mat ); + + m_doc.selection()->clear(); + QPtrListIterator<VLayer> itr( m_doc.layers() ); + + for( ; itr.current(); ++itr ) + { + itr.current()->draw( p, &r ); + } + + p->end(); + delete painterFactory; +} + +void +KarbonPart::setShowStatusBar( bool b ) +{ + m_bShowStatusBar = b; +} + +void +KarbonPart::reorganizeGUI() +{ + QPtrListIterator<KoView> itr( views() ); + + for( ; itr.current(); ++itr ) + { + static_cast<KarbonView*>( itr.current() )->reorganizeGUI(); + } +} + +void +KarbonPart::setUndoRedoLimit( int undos ) +{ + m_commandHistory->setUndoLimit( undos ); + m_commandHistory->setRedoLimit( undos ); +} + +void +KarbonPart::initConfig() +{ + KConfig* config = KarbonPart::instance()->config(); + + if( config->hasGroup( "Interface" ) ) + { + config->setGroup( "Interface" ); + setAutoSave( config->readNumEntry( "AutoSave", defaultAutoSave() / 60 ) * 60 ); + m_maxRecentFiles = config->readNumEntry( "NbRecentFile", 10 ); + setShowStatusBar( config->readBoolEntry( "ShowStatusBar" , true ) ); + setBackupFile( config->readNumEntry( "BackupFile", true ) ); + m_doc.saveAsPath( config->readBoolEntry( "SaveAsPath", true ) ); + } + int undos = 30; + if( config->hasGroup( "Misc" ) ) + { + config->setGroup( "Misc" ); + undos = config->readNumEntry( "UndoRedo", -1 ); + QString defaultUnit = "cm"; + + if( KGlobal::locale()->measureSystem() == KLocale::Imperial ) + defaultUnit = "in"; + + setUnit( KoUnit::unit( config->readEntry( "Units", defaultUnit ) ) ); + m_doc.setUnit( unit() ); + } + if( undos != -1 ) + setUndoRedoLimit( undos ); +} + +bool +KarbonPart::mergeNativeFormat( const QString &file ) +{ + m_merge = true; + bool result = loadNativeFormat( file ); + if ( !result ) + showLoadingErrorDialog(); + m_merge = false; + return result; +} + +void +KarbonPart::addShell( KoMainWindow *shell ) +{ + connect( shell, SIGNAL( documentSaved() ), m_commandHistory, SLOT( documentSaved() ) ); + KoDocument::addShell( shell ); +} + + +void +KarbonPart::slotUnitChanged( KoUnit::Unit /*unit*/ ) +{ +#if 0 + // VDocument has its own storage of the unit... + m_doc.setUnit( unit ); + if( m_toolController->activeTool() ) + m_toolController->activeTool()->refreshUnit(); +#endif +} + +#include "karbon_part.moc" + diff --git a/karbon/karbon_part.h b/karbon/karbon_part.h new file mode 100644 index 00000000..da94d5be --- /dev/null +++ b/karbon/karbon_part.h @@ -0,0 +1,133 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBON_PART_H__ +#define __KARBON_PART_H__ + + +#include <qptrlist.h> + +#include <KoDocument.h> +#include <KoUnit.h> +#include "vdocument.h" +#include "koffice_export.h" + +class DCOPObject; +class KoRect; +class QRect; +class VCommand; +class VDocument; +class VCommandHistory; + +/** + * Keeps track of visual per document properties. + * It manages actions performed on this object in a command history. + * It loads initial settings and applies them to the document and its views. + * Finally a dcop interface is set up here. + */ + +class KARBONCOMMON_EXPORT KarbonPart : public KoDocument +{ + Q_OBJECT +public: + KarbonPart( QWidget* parentWidget = 0L, const char* widgetName = 0L, + QObject* parent = 0L, const char* name = 0L, bool singleViewMode = false ); + virtual ~KarbonPart(); + + virtual void paintContent( QPainter& painter, const QRect& rect, + bool transparent = false, double zoomX = 1.0, double zoomY = 1.0 ); + + /// standard koDocument inherited methods + virtual bool initDoc(InitDocFlags flags, QWidget* parentWidget=0); + + /// file-> open calls this method + virtual bool loadXML( QIODevice*, const QDomDocument& document ); + virtual bool loadOasis( const QDomDocument &doc, KoOasisStyles &styles, const QDomDocument &settings, KoStore *store ); + + /// file-> save and file-> save as call this method + virtual QDomDocument saveXML(); + virtual bool saveOasis( KoStore *store, KoXmlWriter *manifestWriter ); + + virtual void addShell( KoMainWindow *shell ); + + virtual DCOPObject* dcopObject(); + + /// insert a new vobject + void insertObject( VObject* object ); + + /// insert a command into the undo/redo-history: + void addCommand( VCommand* cmd, bool repaint = false ); + + // access static document: + VDocument& document() { return m_doc; } + + // Clear history. + void clearHistory(); + + /// access the command history: + VCommandHistory* commandHistory() + { + return m_commandHistory; + } + + bool showStatusBar() const + { + return m_bShowStatusBar; + } + + void setShowStatusBar( bool b ); + /// update attached view(s) on the current doc settings + /// at this time only the status bar is handled + void reorganizeGUI(); + + void setUndoRedoLimit( int undos ); + + void initConfig(); + unsigned int maxRecentFiles() const { return m_maxRecentFiles; } + + void setPageLayout( KoPageLayout& layout, KoUnit::Unit _unit ); + + bool mergeNativeFormat( const QString & file ); + +public slots: + /// repaint all views attached to this koDocument + void repaintAllViews( bool repaint = true ); + void repaintAllViews( const KoRect& ); + void slotDocumentRestored(); + void slotCommandExecuted( VCommand * ); + void slotUnitChanged( KoUnit::Unit unit ); + +protected: + virtual KoView* createViewInstance( QWidget* parent, const char* name ); + virtual void removeView( KoView *view ); + void saveOasisSettings( KoXmlWriter &/*settingsWriter*/ ); + void loadOasisSettings( const QDomDocument&settingsDoc ); + +private: + VDocument m_doc; /// store non-visual doc info + VCommandHistory* m_commandHistory; /// maintain a command history for undo/redo + + bool m_bShowStatusBar; /// enable/disable status bar in attached view(s) + bool m_merge; + unsigned int m_maxRecentFiles; /// max. number of files shown in open recent menu item + DCOPObject *dcop; +}; + +#endif + diff --git a/karbon/karbon_part_iface.cc b/karbon/karbon_part_iface.cc new file mode 100644 index 00000000..7d187372 --- /dev/null +++ b/karbon/karbon_part_iface.cc @@ -0,0 +1,119 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <dcopclient.h> + +#include <kapplication.h> + +#include "karbon_part.h" +#include "karbon_part_iface.h" +#include "vselection.h" +#include "vlayer.h" + + +KarbonPartIface::KarbonPartIface( KarbonPart* part ) + : KoDocumentIface( part ) +{ + m_part = part; +} + +void KarbonPartIface::selectAllObjects() +{ + m_part->document().selection()->append(); +} + +void KarbonPartIface::deselectAllObjects() +{ + m_part->document().selection()->clear(); +} + +bool KarbonPartIface::showStatusBar () const +{ + return m_part->showStatusBar(); +} + +void KarbonPartIface::setShowStatusBar ( bool b ) +{ + m_part->setShowStatusBar( b ); + m_part->reorganizeGUI(); +} + +void KarbonPartIface::setUndoRedoLimit( int undo ) +{ + m_part->setUndoRedoLimit( undo ); +} + +void KarbonPartIface::initConfig() +{ + m_part->initConfig(); +} + + +void KarbonPartIface::clearHistory() +{ + m_part->clearHistory(); +} + + +QString KarbonPartIface::unitName() const +{ + return m_part->unitName(); +} + +QString +KarbonPartIface::widthInUnits() +{ + QString val = KoUnit::toUserStringValue( m_part->document().width(), m_part->unit() ); + return QString( "%1%2" ).arg( val ).arg( m_part->unitName() ); +} + +QString +KarbonPartIface::heightInUnits() +{ + QString val = KoUnit::toUserStringValue( m_part->document().height(), m_part->unit() ); + return QString( "%1%2" ).arg( val ).arg( m_part->unitName() ); +} + +double +KarbonPartIface::width() +{ + return m_part->document().width(); +} + +double +KarbonPartIface::height() +{ + return m_part->document().height(); +} + +int KarbonPartIface::nbLayer() const +{ + return m_part->document().layers().count(); +} + +DCOPRef KarbonPartIface::activeLayer() +{ + if( !m_part->document().activeLayer() ) + return DCOPRef(); + + return DCOPRef( kapp->dcopClient()->appId(), + m_part->document().activeLayer()->dcopObject()->objId() ); +} + diff --git a/karbon/karbon_part_iface.h b/karbon/karbon_part_iface.h new file mode 100644 index 00000000..8e6e2b20 --- /dev/null +++ b/karbon/karbon_part_iface.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBON_PART_IFACE_H__ +#define __KARBON_PART_IFACE_H__ + + +#include <qstring.h> + +#include <dcopref.h> +#include <KoDocumentIface.h> + + +class KarbonPart; + + +class KarbonPartIface : virtual public KoDocumentIface +{ + K_DCOP + +public: + KarbonPartIface( KarbonPart* part ); + +k_dcop: + void selectAllObjects(); + void deselectAllObjects(); + + bool showStatusBar() const; + void setShowStatusBar( bool b ); + void setUndoRedoLimit( int undo ); + void initConfig(); + void clearHistory(); + QString unitName() const; + QString widthInUnits(); + QString heightInUnits(); + double width(); + double height(); + + int nbLayer() const; + DCOPRef activeLayer(); + +private: + KarbonPart* m_part; +}; + +#endif + diff --git a/karbon/karbon_resourceserver.cc b/karbon/karbon_resourceserver.cc new file mode 100644 index 00000000..af0757a1 --- /dev/null +++ b/karbon/karbon_resourceserver.cc @@ -0,0 +1,571 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qdir.h> +#include <qdom.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qstringlist.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kinstance.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kogradientmanager.h> + +#include "karbon_factory.h" +#include "karbon_resourceserver.h" +#include "vcomposite.h" +#include "vgradient.h" +#include "vgradienttabwidget.h" +#include "vgroup.h" +#include "vobject.h" +#include "vtext.h" +#include "vkopainter.h" +#include "vtransformcmd.h" +#include "shapes/vellipse.h" +#include "shapes/vrectangle.h" +#include "shapes/vsinus.h" +#include "shapes/vspiral.h" +#include "shapes/vstar.h" +#include "shapes/vpolyline.h" +#include "shapes/vpolygon.h" + + +KarbonResourceServer::KarbonResourceServer() +{ + kdDebug(38000) << "-- Karbon ResourceServer --" << endl; + + // PATTERNS + kdDebug(38000) << "Loading patterns:" << endl; + m_patterns.setAutoDelete( true ); + + // image formats + QStringList formats; + formats << "*.png" << "*.tif" << "*.xpm" << "*.bmp" << "*.jpg" << "*.gif"; + + // init vars + QStringList lst; + QString format, file; + + // find patterns + + for( QStringList::Iterator it = formats.begin(); it != formats.end(); ++it ) + { + format = *it; + QStringList l = KarbonFactory::instance()->dirs()->findAllResources( + "kis_pattern", format, false, true ); + lst += l; + } + + // load patterns + for( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) + { + file = *it; + kdDebug(38000) << " - " << file << endl; + loadPattern( file ); + } + + kdDebug(38000) << m_patterns.count() << " patterns loaded." << endl; + + // GRADIENTS + kdDebug(38000) << "Loading gradients:" << endl; + m_gradients = new QPtrList<VGradientListItem>(); + m_gradients->setAutoDelete( true ); + + formats.clear(); + lst.clear(); + formats = KoGradientManager::filters(); + + // find Gradients + + for( QStringList::Iterator it = formats.begin(); it != formats.end(); ++it ) + { + format = *it; + QStringList l = KarbonFactory::instance()->dirs()->findAllResources( + "karbon_gradient", format, false, true ); + lst += l; + } + + // load Gradients + for( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) + { + file = *it; + kdDebug(38000) << " - " << file << endl; + loadGradient( file ); + } + + kdDebug(38000) << m_gradients->count() << " gradients loaded." << endl; + + // CLIPARTS + kdDebug(38000) << "Loading cliparts:" << endl; + m_cliparts = new QPtrList<VClipartIconItem>(); + m_cliparts->setAutoDelete( true ); + + formats.clear(); + lst.clear(); + formats << "*.kclp"; + + // find cliparts + + for( QStringList::Iterator it = formats.begin(); it != formats.end(); ++it ) + { + format = *it; + QStringList l = KarbonFactory::instance()->dirs()->findAllResources( + "karbon_clipart", format, false, true ); + lst += l; + } + + // load cliparts + for( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) + { + file = *it; + kdDebug(38000) << " - " << file << endl; + loadClipart( file ); + } + + m_pixmaps.setAutoDelete( true ); + + kdDebug(38000) << m_cliparts->count() << " cliparts loaded." << endl; +} // KarbonResourceServer::KarbonResourceServer + +KarbonResourceServer::~KarbonResourceServer() +{ + m_patterns.clear(); + m_gradients->clear(); + delete m_gradients; + m_cliparts->clear(); + delete m_cliparts; +} // KarbonResourceServer::~KarbonResourceServer + +const VPattern* +KarbonResourceServer::loadPattern( const QString& filename ) +{ + VPattern* pattern = new VPattern( filename ); + + if( pattern->isValid() ) + m_patterns.append( pattern ); + else + { + delete pattern; + pattern = 0L; + } + + return pattern; +} + +VPattern* +KarbonResourceServer::addPattern( const QString& tilename ) +{ + int i = 1; + QFileInfo fi; + fi.setFile( tilename ); + + if( fi.exists() == false ) + return 0L; + + QString name = fi.baseName(); + + QString ext = '.' + fi.extension( false ); + + QString filename = KarbonFactory::instance()->dirs()->saveLocation( + "kis_pattern" ) + name + ext; + + i = 1; + + fi.setFile( filename ); + + while( fi.exists() == true ) + { + filename = KarbonFactory::instance()->dirs()->saveLocation("kis_pattern" ) + name + i + ext; + fi.setFile( filename ); + kdDebug(38000) << fi.fileName() << endl; + } + + char buffer[ 1024 ]; + QFile in( tilename ); + in.open( IO_ReadOnly ); + QFile out( filename ); + out.open( IO_WriteOnly ); + + while( !in.atEnd() ) + out.writeBlock( buffer, in.readBlock( buffer, 1024 ) ); + + out.close(); + in.close(); + + const VPattern* pattern = loadPattern( filename ); + + if( pattern ) + { + emit patternAdded( m_patterns.last() ); + return static_cast<VPattern*>( m_patterns.last() ); + } + + return 0; +} // KarbonResourceServer::addPattern + +void +KarbonResourceServer::removePattern( VPattern* pattern ) +{ + QFile file( pattern->tilename() ); + + if( file.remove() ) + { + m_patterns.remove( pattern ); + emit patternRemoved( pattern ); + } +} // KarbonResourceServer::removePattern + +VGradientListItem* +KarbonResourceServer::addGradient( VGradient* gradient ) +{ + int i = 1; + char buffer[ 20 ]; + QFileInfo fi; + + sprintf( buffer, "%04d.kgr", i++ ); + fi.setFile( KarbonFactory::instance()->dirs()->saveLocation( "karbon_gradient" ) + buffer ); + + while( fi.exists() == true ) + { + sprintf( buffer, "%04d.kgr", i++ ); + fi.setFile( KarbonFactory::instance()->dirs()->saveLocation( "karbon_gradient" ) + buffer ); + kdDebug(38000) << fi.fileName() << endl; + } + + QString filename = KarbonFactory::instance()->dirs()->saveLocation( "karbon_gradient" ) + buffer; + + saveGradient( gradient, filename ); + + m_gradients->append( new VGradientListItem( *gradient, filename ) ); + + return m_gradients->last(); +} // KarbonResourceServer::addGradient + +void +KarbonResourceServer::removeGradient( VGradientListItem* gradient ) +{ + QFile file( gradient->filename() ); + + if( file.remove() ) + m_gradients->remove( gradient ); +} // KarbonResourceServer::removeGradient + +void +KarbonResourceServer::loadGradient( const QString& filename ) +{ + KoGradientManager gradLoader; + + KoGradient* grad = gradLoader.loadGradient(filename); + + if( !grad ) + return; + + if( grad->colorStops.count() > 1 ) + { + VGradient vgrad; + + vgrad.setOrigin(KoPoint(grad->originX, grad->originY)); + vgrad.setVector(KoPoint(grad->vectorX, grad->vectorY)); + vgrad.setFocalPoint(KoPoint(grad->focalpointX, grad->focalpointY)); + + switch(grad->gradientType) + { + case KoGradientManager::gradient_type_linear: + vgrad.setType(VGradient::linear); + break; + case KoGradientManager::gradient_type_radial: + vgrad.setType(VGradient::radial); + break; + case KoGradientManager::gradient_type_conic: + vgrad.setType(VGradient::conic); + break; + default: return; + } + + switch(grad->gradientRepeatMethod) + { + case KoGradientManager::repeat_method_none: + vgrad.setRepeatMethod(VGradient::none); + break; + case KoGradientManager::repeat_method_reflect: + vgrad.setRepeatMethod(VGradient::reflect); + break; + case KoGradientManager::repeat_method_repeat: + vgrad.setRepeatMethod(VGradient::repeat); + break; + default: return; + } + + vgrad.clearStops(); + + KoColorStop *colstop; + for(colstop = grad->colorStops.first(); colstop; colstop = grad->colorStops.next()) + { + VColor col; + + switch(colstop->colorType) + { + case KoGradientManager::color_type_hsv_ccw: + case KoGradientManager::color_type_hsv_cw: + col.setColorSpace(VColor::hsb, false); + col.set(colstop->color1, colstop->color2, colstop->color3); + break; + case KoGradientManager::color_type_gray: + col.setColorSpace(VColor::gray, false); + col.set(colstop->color1); + break; + case KoGradientManager::color_type_cmyk: + col.setColorSpace(VColor::cmyk, false); + col.set(colstop->color1, colstop->color2, colstop->color3, colstop->color4); + break; + case KoGradientManager::color_type_rgb: + default: + col.set(colstop->color1, colstop->color2, colstop->color3); + } + col.setOpacity(colstop->opacity); + + vgrad.addStop(col, colstop->offset, colstop->midpoint); + } + m_gradients->append( new VGradientListItem( vgrad, filename ) ); + } +} // KarbonResourceServer::loadGradient + +void +KarbonResourceServer::saveGradient( VGradient* gradient, const QString& filename ) +{ + QFile file( filename ); + QDomDocument doc; + QDomElement me = doc.createElement( "PREDEFGRADIENT" ); + doc.appendChild( me ); + gradient->save( me ); + + if( !( file.open( IO_WriteOnly ) ) ) + return ; + + QTextStream ts( &file ); + + doc.save( ts, 2 ); + + file.flush(); + + file.close(); +} // KarbonResourceServer::saveGradient + +VClipartIconItem* +KarbonResourceServer::addClipart( VObject* clipart, double width, double height ) +{ + int i = 1; + char buffer[ 20 ]; + sprintf( buffer, "%04d.kclp", i++ ); + + while( KStandardDirs::exists( KarbonFactory::instance()->dirs()->saveLocation( "karbon_clipart" ) + buffer ) ) + sprintf( buffer, "%04d.kclp", i++ ); + + QString filename = KarbonFactory::instance()->dirs()->saveLocation( "karbon_clipart" ) + buffer; + + saveClipart( clipart, width, height, filename ); + + m_cliparts->append( new VClipartIconItem( clipart, width, height, filename ) ); + + return m_cliparts->last(); +} // KarbonResourceServer::addClipart + +void +KarbonResourceServer::removeClipart( VClipartIconItem* clipart ) +{ + QFile file( clipart->filename() ); + + if( file.remove() ) + m_cliparts->remove + ( clipart ); +} + +void +KarbonResourceServer::loadClipart( const QString& filename ) +{ + QFile f( filename ); + + if( f.open( IO_ReadOnly ) ) + { + QDomDocument doc; + + if( !( doc.setContent( &f ) ) ) + f.close(); + else + { + QDomElement de = doc.documentElement(); + + if( !de.isNull() && de.tagName() == "PREDEFCLIPART" ) + { + VObject* clipart = 0L; + double width = de.attribute( "width", "100.0" ).toFloat(); + double height = de.attribute( "height", "100.0" ).toFloat(); + + QDomNode n = de.firstChild(); + + if( !n.isNull() ) + { + QDomElement e; + e = n.toElement(); + + if( !e.isNull() ) + { + if( e.tagName() == "TEXT" ) + clipart = new VText( 0L ); + else if( e.tagName() == "COMPOSITE" || e.tagName() == "PATH" ) + clipart = new VPath( 0L ); + else if( e.tagName() == "GROUP" ) + clipart = new VGroup( 0L ); + else if( e.tagName() == "ELLIPSE" ) + clipart = new VEllipse( 0L ); + else if( e.tagName() == "POLYGON" ) + clipart = new VPolygon( 0L ); + else if( e.tagName() == "POLYLINE" ) + clipart = new VPolyline( 0L ); + else if( e.tagName() == "RECT" ) + clipart = new VRectangle( 0L ); + else if( e.tagName() == "SINUS" ) + clipart = new VSinus( 0L ); + else if( e.tagName() == "SPIRAL" ) + clipart = new VSpiral( 0L ); + else if( e.tagName() == "STAR" ) + clipart = new VStar( 0L ); +#ifdef HAVE_KARBONTEXT + else if( e.tagName() == "TEXT" ) + clipart = new VText( 0L ); +#endif + if( clipart ) + clipart->load( e ); + } + + if( clipart ) + m_cliparts->append( new VClipartIconItem( clipart, width, height, filename ) ); + + delete clipart; + } + } + } + } +} + +void +KarbonResourceServer::saveClipart( VObject* clipart, double width, double height, const QString& filename ) +{ + QFile file( filename ); + QDomDocument doc; + QDomElement me = doc.createElement( "PREDEFCLIPART" ); + doc.appendChild( me ); + me.setAttribute( "width", width ); + me.setAttribute( "height", height ); + clipart->save( me ); + + if( !( file.open( IO_WriteOnly ) ) ) + return ; + + QTextStream ts( &file ); + + doc.save( ts, 2 ); + + file.flush(); + + file.close(); +} + +QPixmap * +KarbonResourceServer::cachePixmap( const QString &key, int group_or_size ) +{ + QPixmap *result = 0L; + if( !( result = m_pixmaps[ key ] ) ) + { + result = new QPixmap( KGlobal::iconLoader()->iconPath( key, group_or_size ) ); + m_pixmaps.insert( key, result ); + } + return result; +} + +VClipartIconItem::VClipartIconItem( const VObject* clipart, double width, double height, QString filename ) + : m_filename( filename ), m_width( width ), m_height( height ) +{ + m_clipart = clipart->clone(); + m_clipart->setState( VObject::normal ); + + m_pixmap.resize( 64, 64 ); + VKoPainter p( &m_pixmap, 64, 64 ); + QWMatrix mat( 64., 0, 0, 64., 0, 0 ); + + VTransformCmd trafo( 0L, mat ); + trafo.visit( *m_clipart ); + + m_clipart->draw( &p, &m_clipart->boundingBox() ); + + trafo.setMatrix( mat.invert() ); + trafo.visit( *m_clipart ); + + p.end(); + + m_thumbPixmap.resize( 32, 32 ); + VKoPainter p2( &m_thumbPixmap, 32, 32 ); + mat.setMatrix( 32., 0, 0, 32., 0, 0 ); + + trafo.setMatrix( mat ); + trafo.visit( *m_clipart ); + + m_clipart->draw( &p2, &m_clipart->boundingBox() ); + + trafo.setMatrix( mat.invert() ); + trafo.visit( *m_clipart ); + + p2.end(); + + validPixmap = true; + validThumb = true; + + m_delete = QFileInfo( filename ).isWritable(); +} + + +VClipartIconItem::VClipartIconItem( const VClipartIconItem& item ) + : KoIconItem( item ) +{ + m_clipart = item.m_clipart->clone(); + m_filename = item.m_filename; + m_delete = item.m_delete; + m_pixmap = item.m_pixmap; + m_thumbPixmap = item.m_thumbPixmap; + validPixmap = item.validPixmap; + validThumb = item.validThumb; + m_width = item.m_width; + m_height = item.m_height; +} + +VClipartIconItem::~VClipartIconItem() +{ + delete m_clipart; +} + +VClipartIconItem* VClipartIconItem::clone() +{ + return new VClipartIconItem( *this ); +} + +#include "karbon_resourceserver.moc" diff --git a/karbon/karbon_resourceserver.h b/karbon/karbon_resourceserver.h new file mode 100644 index 00000000..8dbdc35f --- /dev/null +++ b/karbon/karbon_resourceserver.h @@ -0,0 +1,169 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + Original work : + kis_resourceserver.h - part of KImageShop + + Copyright (c) 1999 Matthias Elter <elter@kde.org> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBONRESOURCESERVER_H__ +#define __KARBONRESOURCESERVER_H__ + + +#include <qptrlist.h> +#include <qdict.h> +#include <qstring.h> + +//#include "vgradient.h" +#include "vpattern.h" +#include <koffice_export.h> + +class VGradient; +class VGradientListItem; +class VClipartIconItem; +class VObject; + + +class KARBONCOMMON_EXPORT KarbonResourceServer : public QObject +{ + Q_OBJECT + +public: + KarbonResourceServer(); + virtual ~KarbonResourceServer(); + + int patternCount() + { + return m_patterns.count(); + } + + QPtrList<KoIconItem> patterns() + { + return m_patterns; + } + + VPattern* addPattern( const QString& tilename ); + void removePattern( VPattern* pattern ); + + int gradientCount() + { + return m_gradients->count(); + } + + QPtrList<VGradientListItem>* gradients() + { + return m_gradients; + } + + VGradientListItem* addGradient( VGradient* gradient ); + void removeGradient( VGradientListItem* gradient ); + + int clipartCount() + { + return m_cliparts->count(); + } + + QPtrList<VClipartIconItem>* cliparts() + { + return m_cliparts; + } + + VClipartIconItem* addClipart( VObject* clipart, double width, double height ); + void removeClipart( VClipartIconItem* clipartIcon ); + + QPixmap *cachePixmap( const QString &key, int group_or_size ); + +signals: + void patternAdded( KoIconItem *pattern ); + void patternRemoved( KoIconItem *pattern ); + +protected: + const VPattern* loadPattern( const QString& filename ); + + void loadGradient( const QString& filename ); + void saveGradient( VGradient* gradient, const QString& filename ); + + void loadClipart( const QString& filename ); + void saveClipart( VObject* object, double width, double height, const QString& filename ); + +private: + QPtrList<KoIconItem> m_patterns; + QPtrList<VGradientListItem>* m_gradients; + QPtrList<VClipartIconItem>* m_cliparts; + QDict<QPixmap> m_pixmaps; +}; + +class VClipartIconItem : public KoIconItem +{ +public: + VClipartIconItem( const VObject* clipart, double width, double height, QString filename ); + VClipartIconItem( const VClipartIconItem& item ); + ~VClipartIconItem(); + + virtual QPixmap& thumbPixmap() const + { + return ( QPixmap& ) m_thumbPixmap; + } + + virtual QPixmap& pixmap() const + { + return ( QPixmap& ) m_pixmap; + } + + const VObject* clipart() const + { + return m_clipart; + } + + QString filename() const + { + return m_filename; + } + + bool canDelete() const + { + return m_delete; + } + + double originalWidth() const + { + return m_width; + } + + double originalHeight() const + { + return m_height; + } + + VClipartIconItem* clone(); + +private: + QPixmap m_pixmap; + QPixmap m_thumbPixmap; + VObject* m_clipart; + QString m_filename; + bool m_delete; + double m_width; + double m_height; +} + +; // VClipartIconItem + +#endif + diff --git a/karbon/karbon_tool_factory.cc b/karbon/karbon_tool_factory.cc new file mode 100644 index 00000000..081a9148 --- /dev/null +++ b/karbon/karbon_tool_factory.cc @@ -0,0 +1,30 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "karbon_tool_factory.h" +#include "vtool.h" + +KarbonAbstractToolFactory::KarbonAbstractToolFactory() +{ +} + +KarbonAbstractToolFactory::~KarbonAbstractToolFactory() +{ +} + diff --git a/karbon/karbon_tool_factory.h b/karbon/karbon_tool_factory.h new file mode 100644 index 00000000..c714268a --- /dev/null +++ b/karbon/karbon_tool_factory.h @@ -0,0 +1,54 @@ +/* + Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + Copyright (c) 2005 Sven Langkamp <longamp@reallygood.de> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KARBON_TOOL_FACTORY_H_ +#define KARBON_TOOL_FACTORY_H_ + +#include "kactioncollection.h" +#include "karbon_view.h" +#include <koffice_export.h> +#include <vtool.h> + +class KARBONBASE_EXPORT KarbonAbstractToolFactory +{ +public: + KarbonAbstractToolFactory(); + virtual ~KarbonAbstractToolFactory(); + + virtual VTool * createTool( KActionCollection * ac, KarbonView* view ) = 0; +}; + +template<class T> class KarbonToolFactory : public KarbonAbstractToolFactory +{ +public: + KarbonToolFactory() {} + virtual ~KarbonToolFactory() {} + + virtual VTool * createTool( KActionCollection * ac, KarbonView* view ) + { + VTool * t = new T( view ); + Q_CHECK_PTR(t); + t -> setup(ac); + return t; + } +}; + +#endif // KARBON_TOOL_FACTORY_H_ + diff --git a/karbon/karbon_tool_registry.cc b/karbon/karbon_tool_registry.cc new file mode 100644 index 00000000..c643435b --- /dev/null +++ b/karbon/karbon_tool_registry.cc @@ -0,0 +1,62 @@ +/* + Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + Copyright (c) 2005 Sven Langkamp <longamp@reallygood.de> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <kdebug.h> +#include <kaction.h> +#include <kactioncollection.h> + +#include "vtool.h" +#include "karbon_part.h" +#include "karbon_tool_factory.h" +#include "karbon_tool_registry.h" + +KarbonToolRegistry* KarbonToolRegistry::m_singleton = 0; + +KarbonToolRegistry::KarbonToolRegistry() +{ + kdDebug() << " creating a KarbonToolRegistry" << endl; +} + +KarbonToolRegistry::~KarbonToolRegistry() +{ +} + +KarbonToolRegistry* KarbonToolRegistry::instance() +{ + if(KarbonToolRegistry::m_singleton == 0) + { + KarbonToolRegistry::m_singleton = new KarbonToolRegistry(); + } + return KarbonToolRegistry::m_singleton; +} + +void KarbonToolRegistry::createTools(KActionCollection * ac, KarbonView* view) +{ + Q_ASSERT(view); + + QValueVector<KarbonAbstractToolFactory*>::iterator it; + for ( it = begin(); it != end(); ++it ) + (*it) -> createTool(ac, view); +} + +void KarbonToolRegistry::add(KarbonAbstractToolFactory* factory) +{ + append(factory); +} diff --git a/karbon/karbon_tool_registry.h b/karbon/karbon_tool_registry.h new file mode 100644 index 00000000..7aaa6107 --- /dev/null +++ b/karbon/karbon_tool_registry.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + Copyright (c) 2005 Sven Langkamp <longamp@reallygood.de> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KARBON_TOOL_REGISTRY_H_ +#define KARBON_TOOL_REGISTRY_H_ + +#include <qvaluevector.h> +#include <koffice_export.h> +class KActionCollection; +class VTool; +class KarbonView; +class KarbonAbstractToolFactory; + +/** + * A registry where new tool plugins can register themselves. + */ +class KARBONBASE_EXPORT KarbonToolRegistry : private QValueVector<KarbonAbstractToolFactory*> +{ +public: + virtual ~KarbonToolRegistry(); + + static KarbonToolRegistry* instance(); + + void createTools( KActionCollection * ac, KarbonView* view ); + void add(KarbonAbstractToolFactory* factory); + +private: + KarbonToolRegistry(); + KarbonToolRegistry(const KarbonToolRegistry&); + KarbonToolRegistry operator=(const KarbonToolRegistry&); + + static KarbonToolRegistry *m_singleton; +}; + +#endif // KARBON_TOOL_REGISTRY_H_ + diff --git a/karbon/karbon_view.cc b/karbon/karbon_view.cc new file mode 100644 index 00000000..3eb1c19c --- /dev/null +++ b/karbon/karbon_view.cc @@ -0,0 +1,1552 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "karbon_view.h" + +#include <qdragobject.h> +#include <qiconset.h> +#include <qapplication.h> +#include <qclipboard.h> +#include <qpopupmenu.h> +#include <qpaintdevicemetrics.h> +#include <qpainter.h> + +#include <kaction.h> +#include <kcolordrag.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kdeversion.h> +#include <kprinter.h> + +#include <KoMainWindow.h> +#include <KoFilterManager.h> +#include <kstatusbar.h> +#include <kfiledialog.h> +#include <kstdaction.h> +#include <KoContextCelp.h> +#include <KoUnitWidgets.h> +#include <KoPageLayoutDia.h> +#include <vruler.h> +#include <Kolinestyleaction.h> + +// Commands. +#include "valigncmd.h" +#include "vcleanupcmd.h" +#include "vclipartcmd.h" +#include "vclosepathcmd.h" +#include "vdeletecmd.h" +#include "vdistributecmd.h" +#include "vfillcmd.h" +#include "vgroupcmd.h" +#include "vstrokecmd.h" +#include "vtransformcmd.h" +#include "vinsertcmd.h" +#include "vungroupcmd.h" +#include "vzordercmd.h" + +// Dialogs. +#include "vconfiguredlg.h" + +// Dockers. +#include <kopalettemanager.h> +#include "vcolordocker.h" +#include "vdocumentdocker.h" +#include "vstrokedocker.h" +#include "vstyledocker.h" +#include "vtransformdocker.h" + +// ToolBars +//#include "vselecttoolbar.h" + +// Statusbar +#include "vsmallpreview.h" + +// The rest. +#include "karbon_factory.h" +#include "karbon_part.h" +#include "karbon_view_iface.h" +#include "vglobal.h" +#include "vselection.h" +#include "vtool.h" +#include "vtoolcontroller.h" +#include "vcomposite.h" +#include "vgroup.h" +#include "vpainterfactory.h" +#include "vqpainter.h" +#include "vkopainter.h" +#include "vstrokefillpreview.h" +#include "vtypebuttonbox.h" +#include "vstatebutton.h" +#include "vcanvas.h" +#include "vtoolbox.h" +#include "karbon_drag.h" +// #include "vselectnodestool.h" + +#include <unistd.h> + +// Only for debugging. +#include <kdebug.h> + +const int rulerWidth = 20; // vertical ruler width +const int rulerHeight = 20; // horizontal ruler height + +KarbonView::KarbonView( KarbonPart* p, QWidget* parent, const char* name ) + : KoView( p, parent, name ), KXMLGUIBuilder( shell() ), m_part( p ) +{ + m_toolbox = 0L; + m_toolController = new VToolController( this ); + m_toolController->init(); + + setInstance( KarbonFactory::instance(), true ); + + setClientBuilder( this ); + + if( !p->isReadWrite() ) + setXMLFile( QString::fromLatin1( "karbon_readonly.rc" ) ); + else + setXMLFile( QString::fromLatin1( "karbon.rc" ) ); + + m_dcop = 0L; + dcopObject(); // build it + + // set up status bar message + m_status = new KStatusBarLabel( QString::null, 0, statusBar() ); + m_status->setAlignment( AlignLeft | AlignVCenter ); + m_status->setMinimumWidth( 300 ); + addStatusBarItem( m_status, 1 ); + m_cursorCoords = new KStatusBarLabel( QString::null, 0, statusBar() ); + m_cursorCoords->setAlignment( AlignLeft | AlignVCenter ); + m_cursorCoords->setMinimumWidth( 50 ); + addStatusBarItem( m_cursorCoords, 0 ); + m_smallPreview = new VSmallPreview( this, name ); + addStatusBarItem( m_smallPreview ); + + initActions(); + + m_DocumentTab = 0L; + m_LayersTab = 0L; + m_HistoryTab = 0L; + m_strokeFillPreview = 0L; + m_ColorManager = 0L; + m_strokeDocker = 0L; + m_styleDocker = 0L; + m_TransformDocker = 0L; + + // set selectTool by default + //m_toolbox->slotPressButton( 0 ); + + m_pPaletteManager = new KoPaletteManager(this, actionCollection(), "karbon palette manager"); + + unsigned int max = part()->maxRecentFiles(); + setNumberOfRecentFiles( max ); + + reorganizeGUI(); + + connect( p, SIGNAL( unitChanged( KoUnit::Unit ) ), this, SLOT( setUnit( KoUnit::Unit ) ) ); + + // widgets: + m_horizRuler = new VRuler( Qt::Horizontal, this ); + m_horizRuler->setUnit(p->unit()); + connect( p, SIGNAL( unitChanged( KoUnit::Unit ) ), m_horizRuler, SLOT( setUnit( KoUnit::Unit ) ) ); + + m_vertRuler = new VRuler( Qt::Vertical, this ); + m_vertRuler->setUnit(p->unit()); + connect( p, SIGNAL( unitChanged( KoUnit::Unit ) ), m_vertRuler, SLOT( setUnit( KoUnit::Unit ) ) ); + + m_canvas = new VCanvas( this, this, p ); + connect( m_canvas, SIGNAL( contentsMoving( int, int ) ), this, SLOT( canvasContentsMoving( int, int ) ) ); + + m_canvas->show(); + + // set up factory + m_painterFactory = new VPainterFactory; + m_painterFactory->setPainter( canvasWidget()->pixmap(), width(), height() ); + m_painterFactory->setEditPainter( canvasWidget()->viewport(), width(), height() ); + + if( shell() ) + { + //Create Dockers + createColorDock(); + createStrokeDock(); + createTransformDock(); + createDocumentTabDock(); + createLayersTabDock(); + createHistoryTabDock(); + createResourceDock(); + + if( m_showRulerAction->isChecked() ) + { + m_horizRuler->show(); + m_vertRuler->show(); + } + else + { + m_horizRuler->hide(); + m_vertRuler->hide(); + } + + m_horizRuler->installEventFilter(m_canvas); + m_vertRuler->installEventFilter(m_canvas); + } + + zoomChanged(); +} + +KarbonView::~KarbonView() +{ + kdDebug(38000) << "Handling KarbonView dtor" << endl; + + // widgets: + delete m_smallPreview; + delete m_status; + delete m_cursorCoords; + + delete m_painterFactory; + + delete m_canvas; + + delete m_dcop; + + delete m_toolController; +} + +static Qt::Dock stringToDock( const QString& attrPosition ) +{ + KToolBar::Dock dock = KToolBar::DockTop; + if ( !attrPosition.isEmpty() ) { + if ( attrPosition == "top" ) + dock = Qt::DockTop; + else if ( attrPosition == "left" ) + dock = Qt::DockLeft; + else if ( attrPosition == "right" ) + dock = Qt::DockRight; + else if ( attrPosition == "bottom" ) + dock = Qt::DockBottom; + else if ( attrPosition == "floating" ) + dock = Qt::DockTornOff; + else if ( attrPosition == "flat" ) + dock = Qt::DockMinimized; + } + + return dock; +} + +QWidget * +KarbonView::createContainer( QWidget *parent, int index, const QDomElement &element, int &id ) +{ + if( element.attribute( "name" ) == "Tools" ) + { + m_toolbox = new VToolBox( mainWindow(), "Tools", KarbonFactory::instance() ); + toolController()->setUp( actionCollection(), m_toolbox ); + + kdDebug() << "Toolbox position: " << element.attribute( "position" ) << "\n"; + Dock dock = stringToDock( element.attribute( "position" ).lower() ); + + mainWindow()->addDockWindow( m_toolbox, dock, false); + mainWindow()->moveDockWindow( m_toolbox, dock, false, 0, 0 ); + + //connect( m_toolbox, SIGNAL( activeToolChanged( VTool * ) ), this, SLOT( slotActiveToolChanged( VTool * ) ) ); + + if( shell() ) + { + m_strokeFillPreview = new VStrokeFillPreview( part(), m_toolbox ); + m_typeButtonBox = new VTypeButtonBox( part(), m_toolbox ); + + connect( m_strokeFillPreview, SIGNAL( fillSelected() ), m_typeButtonBox, SLOT( setFill() ) ); + connect( m_strokeFillPreview, SIGNAL( strokeSelected() ), m_typeButtonBox, SLOT( setStroke() ) ); + + connect( m_strokeFillPreview, SIGNAL( strokeChanged( const VStroke & ) ), this, SLOT( slotStrokeChanged( const VStroke & ) ) ); + connect( m_strokeFillPreview, SIGNAL( fillChanged( const VFill & ) ), this, SLOT( slotFillChanged( const VFill & ) ) ); + + connect( m_strokeFillPreview, SIGNAL( strokeSelected() ), m_ColorManager, SLOT( setStrokeDocker() ) ); + connect( m_strokeFillPreview, SIGNAL( fillSelected( ) ), m_ColorManager, SLOT( setFillDocker() ) ); + + connect( m_part->commandHistory(), SIGNAL( commandExecuted( VCommand* ) ), this, SLOT( commandExecuted( VCommand* ) ) ); + + connect( m_ColorManager, SIGNAL(modeChanged( KDualColorButton::DualColor)), this, SLOT( strokeFillSelectionChanged(KDualColorButton::DualColor) ) ); + connect( m_ColorManager, SIGNAL(bgColorChanged( const QColor & )), this, SLOT(colorChanged( const QColor & )) ); + connect( m_ColorManager, SIGNAL(fgColorChanged( const QColor & )), this, SLOT(colorChanged( const QColor & )) ); + selectionChanged(); + + //create toolbars +// m_selectToolBar = new VSelectToolBar( this, "selecttoolbar" ); +// mainWindow()->addToolBar( m_selectToolBar ); + } + } + + return KXMLGUIBuilder::createContainer( parent, index, element, id ); +} + +void +KarbonView::removeContainer( QWidget *container, QWidget *parent, + QDomElement &element, int id ) +{ + if( container ) + kdDebug(38000) << container << endl; + + if( shell() && container == m_toolbox ) + { + disconnect( m_part->commandHistory(), SIGNAL( commandExecuted( VCommand* ) ), this, SLOT( commandExecuted( VCommand* ) ) ); + disconnect( m_ColorManager, SIGNAL(modeChanged( KDualColorButton::DualColor)), this, SLOT( strokeFillSelectionChanged(KDualColorButton::DualColor) ) ); + disconnect( m_ColorManager, SIGNAL(bgColorChanged( const QColor & )), this, SLOT(colorChanged( const QColor & )) ); + disconnect( m_ColorManager, SIGNAL(fgColorChanged( const QColor & )), this, SLOT(colorChanged( const QColor & )) ); + delete m_toolbox; + m_toolbox = 0L; + m_toolController->youAintGotNoToolBox(); +// delete m_strokeFillPreview; + m_strokeFillPreview = 0; +// delete m_typeButtonBox; + m_typeButtonBox = 0; +// delete m_selectToolBar; +// m_selectToolBar = 0L; + } + else + KXMLGUIBuilder::removeContainer( container, parent, element, id ); +} + + +DCOPObject * +KarbonView::dcopObject() +{ + if( !m_dcop ) + m_dcop = new KarbonViewIface( this ); + + return m_dcop; +} + +QWidget* +KarbonView::canvas() const +{ + return m_canvas; +} + +void +KarbonView::resizeEvent( QResizeEvent* /*event*/ ) +{ + if( shell() && m_showRulerAction->isChecked()) + { + m_canvas->setGeometry( rulerWidth, rulerHeight, width() - rulerWidth, height() - rulerHeight ); + updateRuler(); + } + else + { + m_horizRuler->hide(); + m_vertRuler->hide(); + m_canvas->setGeometry( 0, 0, width(), height() ); + } + + zoomChanged(); + reorganizeGUI(); +} + +void +KarbonView::dropEvent( QDropEvent *e ) +{ + //Accepts QColor - from Color Manager's KColorPatch + QColor color; + VColor realcolor; + VObjectList selection; + + if( KColorDrag::decode( e, color ) ) + { + float r = color.red() / 255.0; + float g = color.green() / 255.0; + float b = color.blue() / 255.0; + + realcolor.set( r, g, b ); + + if( part() ) + if( m_strokeFillPreview->strokeIsSelected() ) + part()->addCommand( new VStrokeCmd( &part()->document(), realcolor ), true ); + else + part()->addCommand( new VFillCmd( &part()->document(), realcolor ), true ); + } + else if( KarbonDrag::decode( e, selection, m_part->document() ) ) + { + VObject *clipart = selection.first(); + KoPoint p( e->pos() ); + p = m_canvas->toContents( p ); + QWMatrix mat( 1, 0, 0, 1, p.x(), p.y() ); + + VTransformCmd trafo( 0L, mat ); + trafo.visit( *clipart ); + VClipartCmd* cmd = new VClipartCmd( &m_part->document(), i18n( "Insert Clipart" ), clipart ); + + m_part->addCommand( cmd, true ); + } +} + +void +KarbonView::print( KPrinter &printer ) +{ + // TODO : ultimately use plain QPainter here as that is better suited to print system + kdDebug(38000) << "KarbonView::print" << endl; + + QPaintDeviceMetrics metrics( ( QPaintDevice * ) & printer ); + printer.setFullPage( true ); + + KoPageLayout pageLayout = part()->pageLayout(); + printer.setOrientation( pageLayout.orientation == PG_PORTRAIT ? KPrinter::Portrait : KPrinter::Landscape ); + printer.setPageSize( (KPrinter::PageSize)KoPageFormat::printerPageSize( pageLayout.format ) ); + + // we are using 72 dpi internally + double zoom = metrics.logicalDpiX() / 72.0; + + QWMatrix mat; + mat.scale( 1, -1 ); + mat.translate( 0, -part()->document().height()*zoom ); + + double w = zoom*part()->document().width(); + double h = zoom*part()->document().height(); + + KoRect rect( 0, 0, w, h ); + + QPixmap img( static_cast<int>( w ), static_cast<int>( h ) ); + + // first use the libarts painter to draw into the pixmap + VKoPainter kop( ( QPaintDevice * )&img, static_cast<int>( w ), static_cast<int>( h ) ); + + kop.setZoomFactor( zoom ); + kop.setWorldMatrix( mat ); + + kop.begin(); + + part()->document().draw( &kop, &rect ); + + kop.end(); + + QPainter p; + + // us kopainter to draw the pixmap + // note that it is looking unsmooth when previewing, + // but the print is actually ok as we are printing at 100% zoom anyway + p.begin( &printer ); + p.drawPixmap( 0, 0, img ); + p.end(); +} + +void +KarbonView::fileImportGraphic() +{ + QStringList filter; + filter << "application/x-karbon" << "image/svg+xml" << "image/x-wmf" << "image/x-eps" << "application/postscript"; + KFileDialog *dialog = new KFileDialog( "foo", QString::null, 0L, "Choose Graphic to Add", true); + dialog->setMimeFilter( filter, "application/x-karbon" ); + if(dialog->exec()!=QDialog::Accepted) { + delete dialog; + return; + } + QString fname = dialog->selectedFile(); + //kdDebug(38000) << "in : " << fname.latin1() << endl; + //kdDebug(38000) << "part()->document()->nativeFormatMimeType().latin1() : " << part()->nativeFormatMimeType() << endl; + //kdDebug(38000) << "dialog->currentMimeFilter().latin1() : " << dialog->currentMimeFilter().latin1() << endl; + if( part()->nativeFormatMimeType() == dialog->currentMimeFilter().latin1() ) + part()->mergeNativeFormat( fname ); + else + { + KoFilterManager man( part() ); + KoFilter::ConversionStatus status; + QString importedFile = man.import( fname, status ); + part()->mergeNativeFormat( importedFile ); + if( !importedFile.isEmpty() ) + unlink( QFile::encodeName( importedFile ) ); + } + delete dialog; + part()->repaintAllViews(); +} + +void +KarbonView::editCut() +{ + addSelectionToClipboard(); + // remove selection + editDeleteSelection(); +} + +void +KarbonView::editCopy() +{ + addSelectionToClipboard(); +} + +void +KarbonView::addSelectionToClipboard() const +{ + if( part()->document().selection()->objects().count() <= 0 ) + return; + + KarbonDrag* kd = new KarbonDrag(); + kd->setObjectList( part()->document().selection()->objects() ); + QApplication::clipboard()->setData( kd ); +} + +void +KarbonView::editPaste() +{ + KarbonDrag kd; + VObjectList objects; + + if( !kd.decode( QApplication::clipboard()->data(), objects, part()->document() ) ) + return; + + // Paste with a small offset. + double copyOffset = part()->instance()->config()->readNumEntry( "CopyOffset", 10 ); + part()->addCommand( new VInsertCmd( &part()->document(), + objects.count() == 1 + ? i18n( "Paste Object" ) + : i18n( "Paste Objects" ), + &objects, copyOffset ), + true ); + + part()->repaintAllViews(); + selectionChanged(); +} + +void +KarbonView::editSelectAll() +{ + part()->document().selection()->append(); + + if( part()->document().selection()->objects().count() > 0 ) + part()->repaintAllViews(); + + selectionChanged(); +} + +void +KarbonView::editDeselectAll() +{ + if( part()->document().selection()->objects().count() > 0 ) + { + part()->document().selection()->clear(); + part()->repaintAllViews(); + } + + selectionChanged(); +} + +void +KarbonView::editDeleteSelection() +{ + kdDebug(38000) << "*********" << endl; + + if( part()->document().selection()->objects().count() > 0 ) + { + part()->addCommand( + new VDeleteCmd( &part()->document() ), + true ); + } +} + +void +KarbonView::editPurgeHistory() +{ + // TODO: check for history size != 0 + + if( KMessageBox::warningContinueCancel( this, + i18n( "This action cannot be undone later. Do you really want to continue?" ), + i18n( "Purge History" ), + KStdGuiItem::del(), + "edit_purge_history" ) ) + { + // Use the VCleanUp command to remove "deleted" + // objects from all layers. + VCleanUpCmd cmd( &part()->document() ); + cmd.execute(); + + part()->clearHistory(); + } +} + +void +KarbonView::selectionAlignHorizontalLeft() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_HORIZONTAL_LEFT ), true ); +} +void +KarbonView::selectionAlignHorizontalCenter() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_HORIZONTAL_CENTER ), true ); +} + +void +KarbonView::selectionAlignHorizontalRight() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_HORIZONTAL_RIGHT ), true ); +} + +void +KarbonView::selectionAlignVerticalTop() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_VERTICAL_TOP ), true ); +} + +void +KarbonView::selectionAlignVerticalCenter() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_VERTICAL_CENTER ), true ); +} + +void +KarbonView::selectionAlignVerticalBottom() +{ + part()->addCommand( + new VAlignCmd( &part()->document(), VAlignCmd::ALIGN_VERTICAL_BOTTOM ), true ); +} + +void +KarbonView::selectionDistributeHorizontalCenter() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_HORIZONTAL_CENTER ), true ); +} + +void +KarbonView::selectionDistributeHorizontalGap() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_HORIZONTAL_GAP ), true ); +} + +void +KarbonView::selectionDistributeHorizontalLeft() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_HORIZONTAL_LEFT ), true ); +} + +void +KarbonView::selectionDistributeHorizontalRight() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_HORIZONTAL_RIGHT ), true ); +} + +void +KarbonView::selectionDistributeVerticalCenter() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_VERTICAL_CENTER ), true ); +} + +void +KarbonView::selectionDistributeVerticalGap() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_VERTICAL_GAP ), true ); +} + +void +KarbonView::selectionDistributeVerticalBottom() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_VERTICAL_BOTTOM ), true ); +} + +void +KarbonView::selectionDistributeVerticalTop() +{ + part()->addCommand( + new VDistributeCmd( &part()->document(), VDistributeCmd::DISTRIBUTE_VERTICAL_TOP ), true ); +} + +void +KarbonView::selectionDuplicate() +{ + if ( !part()->document().selection()->objects().count() ) + return; + + VObjectList objects; + + // Create copies of all the objects and not just the list. + VObjectListIterator itr( part()->document().selection()->objects() ); + for ( ; itr.current() ; ++itr ) { + objects.append( itr.current()->clone() ); + } + + // Paste with a small offset. + double copyOffset = part()->instance()->config()->readNumEntry( "CopyOffset", 10 ); + part()->addCommand( new VInsertCmd( &part()->document(), + objects.count() == 1 + ? i18n( "Duplicate Object" ) + : i18n( "Duplicate Objects" ), + &objects, copyOffset ), + true ); + + part()->repaintAllViews(); + selectionChanged(); +} + +void +KarbonView::selectionBringToFront() +{ + part()->addCommand( + new VZOrderCmd( &part()->document(), VZOrderCmd::bringToFront ), true ); +} + +void +KarbonView::selectionMoveUp() +{ + part()->addCommand( + new VZOrderCmd( &part()->document(), VZOrderCmd::up ), true ); +} + +void +KarbonView::selectionMoveDown() +{ + part()->addCommand( + new VZOrderCmd( &part()->document(), VZOrderCmd::down ), true ); +} + +void +KarbonView::selectionSendToBack() +{ + part()->addCommand( + new VZOrderCmd( &part()->document(), VZOrderCmd::sendToBack ), true ); +} + +void +KarbonView::groupSelection() +{ + part()->addCommand( new VGroupCmd( &part()->document() ), true ); +} + +void +KarbonView::ungroupSelection() +{ + part()->addCommand( new VUnGroupCmd( &part()->document() ), true ); +} + +void +KarbonView::closePath() +{ + part()->addCommand( new VClosePathCmd( &part()->document() ), true ); +} + +void +KarbonView::slotActiveToolChanged( VTool *tool ) +{ + toolController()->setCurrentTool( tool ); + + m_canvas->repaintAll(); +} + +void +KarbonView::viewModeChanged() +{ + canvasWidget()->pixmap()->fill(); + + if( m_viewAction->currentItem() == 1 ) + m_painterFactory->setWireframePainter( canvasWidget()->pixmap(), width(), height() ); + else + m_painterFactory->setPainter( canvasWidget()->pixmap(), width(), height() ); + + m_canvas->repaintAll(); +} + +void +KarbonView::setZoomAt( double zoom, const KoPoint &p ) +{ + QString zoomText = QString( "%1%" ).arg( zoom * 100.0, 0, 'f', 2 ); + QStringList stl = m_zoomAction->items(); + if( stl.first() == "25%" ) + { + stl.prepend( zoomText.latin1() ); + m_zoomAction->setItems( stl ); + m_zoomAction->setCurrentItem( 0 ); + } + else + { + m_zoomAction->setCurrentItem( 0 ); + m_zoomAction->changeItem( m_zoomAction->currentItem(), zoomText.latin1() ); + } + zoomChanged( p ); +} + +void +KarbonView::viewZoomIn() +{ + setZoomAt( zoom() * 1.50 ); +} + +void +KarbonView::viewZoomOut() +{ + setZoomAt( zoom() * 0.75 ); +} + +void +KarbonView::zoomChanged( const KoPoint &p ) +{ + double centerX; + double centerY; + double zoomFactor; + + if( !p.isNull() ) + { + centerX = ( ( p.x() ) * zoom() + m_canvas->pageOffsetX() ) / double( m_canvas->contentsWidth() ); + centerY = 1 - ( ( p.y() ) * zoom() + m_canvas->pageOffsetY() ) / double( m_canvas->contentsHeight() ); + zoomFactor = m_zoomAction->currentText().remove( '%' ).toDouble() / 100.0; + } + else if( m_zoomAction->currentText() == i18n("Zoom Width") ) + { + centerX = 0.5; + centerY = double( m_canvas->contentsY() + 0.5 * m_canvas->visibleHeight() ) / double( m_canvas->contentsHeight() ); + zoomFactor = double( m_canvas->visibleWidth() ) / double( part()->document().width() ); + } + else if( m_zoomAction->currentText() == i18n("Whole Page") ) + { + centerX = 0.5; + centerY = 0.5; + double zoomFactorX = double( m_canvas->visibleWidth() ) / double( part()->document().width() ); + double zoomFactorY = double( m_canvas->visibleHeight() ) / double( part()->document().height() ); + + if(zoomFactorX < 0 && zoomFactorY > 0) + zoomFactor = zoomFactorY; + else if(zoomFactorX > 0 && zoomFactorY < 0) + zoomFactor = zoomFactorX; + else if(zoomFactorX < 0 && zoomFactorY < 0) + zoomFactor = 0.0001; + else + zoomFactor = kMin( zoomFactorX, zoomFactorY ); + } + else + { + if( m_canvas->contentsWidth() > m_canvas->visibleWidth() ) + centerX = double( m_canvas->contentsX() + 0.5 * m_canvas->visibleWidth() ) / double( m_canvas->contentsWidth() ); + else + centerX = 0.5; + if( m_canvas->contentsHeight() > m_canvas->visibleHeight() ) + centerY = double( m_canvas->contentsY() + 0.5 * m_canvas->visibleHeight() ) / double( m_canvas->contentsHeight() ); + else + centerY = 0.5; + zoomFactor = m_zoomAction->currentText().remove( '%' ).toDouble() / 100.0; + } + kdDebug(38000) << "centerX : " << centerX << endl; + kdDebug(38000) << "centerY : " << centerY << endl; + kdDebug(38000) << "zoomFactor : " << zoomFactor << endl; + if( zoomFactor == 0.0 ) return; + + // above 2000% probably doesn't make sense... (Rob) + if( zoomFactor > 20 ) + { + zoomFactor = 20; + m_zoomAction->changeItem( m_zoomAction->currentItem(), " 2000%" ); + } + + KoView::setZoom( zoomFactor ); + + m_canvas->viewport()->setUpdatesEnabled( false ); + + m_canvas->resizeContents( int( ( part()->pageLayout().ptWidth + 300 ) * zoomFactor ), + int( ( part()->pageLayout().ptHeight + 460 ) * zoomFactor ) ); + + + VPainter *painter = painterFactory()->editpainter(); + painter->setZoomFactor( zoomFactor ); + + m_canvas->setViewport( centerX, centerY ); + m_canvas->repaintAll(); + m_canvas->viewport()->setUpdatesEnabled( true ); + + + if( shell() && m_showRulerAction->isChecked() ) + { + m_horizRuler->setZoom( zoomFactor ); + m_vertRuler->setZoom( zoomFactor ); + m_canvas->setGeometry( rulerWidth, rulerHeight, width() - rulerWidth, height() - rulerHeight ); + updateRuler(); + } + else + { + m_horizRuler->hide(); + m_vertRuler->hide(); + } + m_canvas->viewport()->setFocus(); + + emit zoomChanged( zoomFactor ); +} + +void +KarbonView::setLineStyle( int style ) +{ + QValueList<float> dashes; + if( style == Qt::NoPen ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes << 0 << 20 ), true ); + else if( style == Qt::SolidLine ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes ), true ); + else if( style == Qt::DashLine ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes << 12 << 6 ), true ); + else if( style == Qt::DotLine ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes << 2 << 2 ), true ); + else if( style == Qt::DashDotLine ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes << 12 << 2 << 2 << 2 ), true ); + else if( style == Qt::DashDotDotLine ) + part()->addCommand( new VStrokeCmd( &part()->document(), dashes << 12 << 2 << 2 << 2 << 2 << 2 ), true ); +} + +void +KarbonView::slotStrokeChanged( const VStroke &c ) +{ + part()->document().selection()->setStroke( c ); + selectionChanged(); +} + +void +KarbonView::slotFillChanged( const VFill &f ) +{ + part()->document().selection()->setFill( f ); + selectionChanged(); +} + +void +KarbonView::setLineWidth() +{ + setLineWidth( m_setLineWidth->value() ); + selectionChanged(); +} + +//necessary for dcop call ! +void +KarbonView::setLineWidth( double val ) +{ + part()->addCommand( new VStrokeCmd( &part()->document(), val ), true ); +} + +void +KarbonView::initActions() +{ + // view -----> + m_viewAction = new KSelectAction( + i18n( "View &Mode" ), 0, this, + SLOT( viewModeChanged() ), actionCollection(), "view_mode" ); + + m_zoomAction = new KSelectAction( + i18n( "&Zoom" ), "viewmag", 0, this, + SLOT( zoomChanged() ), actionCollection(), "view_zoom" ); + + QStringList mstl; + mstl << i18n( "Normal" ) << i18n( "Wireframe" ); + m_viewAction->setItems( mstl ); + m_viewAction->setCurrentItem( 0 ); + m_viewAction->setEditable( false ); + + QStringList stl; + // xgettext:no-c-format + stl << i18n( "25%" ); + // xgettext:no-c-format + stl << i18n( "50%" ); + // xgettext:no-c-format + stl << i18n( "100%" ); + // xgettext:no-c-format + stl << i18n( "200%" ); + // xgettext:no-c-format + stl << i18n( "300%" ); + // xgettext:no-c-format + stl << i18n( "400%" ); + // xgettext:no-c-format + stl << i18n( "800%" ); + stl << i18n( "Whole Page" ) + << i18n( "Zoom Width" ); + + m_zoomAction->setItems( stl ); + m_zoomAction->setEditable( true ); + m_zoomAction->setCurrentItem( 7 ); + + KStdAction::zoomIn( this, SLOT( viewZoomIn() ), actionCollection(), "view_zoom_in" ); + KStdAction::zoomOut( this, SLOT( viewZoomOut() ), actionCollection(), "view_zoom_out" ); + + m_showPageMargins = new KToggleAction( i18n("Show Page Margins"), "view_margins", 0, actionCollection(), "view_show_margins" ); + connect( m_showPageMargins, SIGNAL(toggled(bool)), SLOT(togglePageMargins(bool))); +#if KDE_IS_VERSION(3,2,90) + m_showPageMargins->setCheckedState(i18n("Hide Page Margins")); +#endif + + // No need for the other actions in read-only (embedded) mode + if( !shell() ) + return; + + // edit -----> + KStdAction::cut( this, + SLOT( editCut() ), actionCollection(), "edit_cut" ); + KStdAction::copy( this, + SLOT( editCopy() ), actionCollection(), "edit_copy" ); + KStdAction::paste( this, + SLOT( editPaste() ), actionCollection(), "edit_paste" ); + KStdAction::selectAll( this, SLOT( editSelectAll() ), actionCollection(), "edit_select_all" ); + KStdAction::deselect( this, SLOT( editDeselectAll() ), actionCollection(), "edit_deselect_all" ); + + new KAction( + i18n( "&Import Graphic..." ), 0, 0, this, + SLOT( fileImportGraphic() ), actionCollection(), "file_import" ); + m_deleteSelectionAction = new KAction( + i18n( "D&elete" ), "editdelete", QKeySequence( "Del" ), this, + SLOT( editDeleteSelection() ), actionCollection(), "edit_delete" ); + new KAction( + i18n( "&History" ), 0, 0, this, + SLOT( editPurgeHistory() ), actionCollection(), "edit_purge_history" ); + // edit <----- + + // object -----> + new KAction( + i18n( "&Duplicate" ), "duplicate", QKeySequence( "Ctrl+D" ), this, + SLOT( selectionDuplicate() ), actionCollection(), "object_duplicate" ); + new KAction( + i18n( "Bring to &Front" ), "bring_forward", QKeySequence( "Ctrl+Shift+]" ), this, + SLOT( selectionBringToFront() ), actionCollection(), "object_move_totop" ); + new KAction( + i18n( "&Raise" ), "raise", QKeySequence( "Ctrl+]" ), this, + SLOT( selectionMoveUp() ), actionCollection(), "object_move_up" ); + new KAction( + i18n( "&Lower" ), "lower", QKeySequence( "Ctrl+[" ), this, + SLOT( selectionMoveDown() ), actionCollection(), "object_move_down" ); + new KAction( + i18n( "Send to &Back" ), "send_backward", QKeySequence( "Ctrl+Shift+[" ), this, + SLOT( selectionSendToBack() ), actionCollection(), "object_move_tobottom" ); + + new KAction( + i18n( "Align Left" ), "aoleft", 0, this, + SLOT( selectionAlignHorizontalLeft() ), + actionCollection(), "object_align_horizontal_left" ); + new KAction( + i18n( "Align Center (Horizontal)" ), "aocenterh", 0, this, + SLOT( selectionAlignHorizontalCenter() ), + actionCollection(), "object_align_horizontal_center" ); + new KAction( + i18n( "Align Right" ), "aoright", 0, this, + SLOT( selectionAlignHorizontalRight() ), + actionCollection(), "object_align_horizontal_right" ); + new KAction( + i18n( "Align Top" ), "aotop", 0, this, + SLOT( selectionAlignVerticalTop() ), + actionCollection(), "object_align_vertical_top" ); + new KAction( + i18n( "Align Middle (Vertical)" ), "aocenterv", 0, this, + SLOT( selectionAlignVerticalCenter() ), + actionCollection(), "object_align_vertical_center" ); + new KAction( + i18n( "Align Bottom" ), "aobottom", 0, this, + SLOT( selectionAlignVerticalBottom() ), + actionCollection(), "object_align_vertical_bottom" ); + + new KAction( + i18n( "Distribute Center (Horizontal)" ), "", 0, this, + SLOT( selectionDistributeHorizontalCenter() ), + actionCollection(), "object_distribute_horizontal_center" ); + new KAction( + i18n( "Distribute Gaps (Horizontal)" ), "", 0, this, + SLOT( selectionDistributeHorizontalGap() ), + actionCollection(), "object_distribute_horizontal_gap" ); + new KAction( + i18n( "Distribute Left Borders" ), "", 0, this, + SLOT( selectionDistributeHorizontalLeft() ), + actionCollection(), "object_distribute_horizontal_left" ); + new KAction( + i18n( "Distribute Right Borders" ), "", 0, this, + SLOT( selectionDistributeHorizontalRight() ), + actionCollection(), "object_distribute_horizontal_right" ); + new KAction( + i18n( "Distribute Center (Vertical)" ), "", 0, this, + SLOT( selectionDistributeVerticalCenter() ), + actionCollection(), "object_distribute_vertical_center" ); + new KAction( + i18n( "Distribute Gaps (Vertical)" ), "", 0, this, + SLOT( selectionDistributeVerticalGap() ), + actionCollection(), "object_distribute_vertical_gap" ); + new KAction( + i18n( "Distribute Bottom Borders" ), "", 0, this, + SLOT( selectionDistributeVerticalBottom() ), + actionCollection(), "object_distribute_vertical_bottom" ); + new KAction( + i18n( "Distribute Top Borders" ), "", 0, this, + SLOT( selectionDistributeVerticalTop() ), + actionCollection(), "object_distribute_vertical_top" ); + + m_showRulerAction = new KToggleAction( i18n( "Show Rulers" ), 0, this, SLOT( showRuler() ), actionCollection(), "view_show_ruler" ); +#if KDE_IS_VERSION(3,2,90) + m_showRulerAction->setCheckedState(i18n("Hide Rulers")); +#endif + m_showRulerAction->setToolTip( i18n( "Shows or hides rulers." ) ); + m_showRulerAction->setChecked( false ); + m_showGridAction = new KToggleAction( i18n( "Show Grid" ), "view_grid", this, SLOT( showGrid() ), actionCollection(), "view_show_grid" ); +#if KDE_IS_VERSION(3,2,90) + m_showGridAction->setCheckedState(i18n("Hide Grid")); +#endif + m_showGridAction->setToolTip( i18n( "Shows or hides grid." ) ); + //m_showGridAction->setChecked( true ); + m_snapGridAction = new KToggleAction( i18n( "Snap to Grid" ), 0, this, SLOT( snapToGrid() ), actionCollection(), "view_snap_to_grid" ); + m_snapGridAction->setToolTip( i18n( "Snaps to grid." ) ); + //m_snapGridAction->setChecked( true ); + m_groupObjects = new KAction( + i18n( "&Group Objects" ), "group", QKeySequence( "Ctrl+G" ), this, + SLOT( groupSelection() ), actionCollection(), "selection_group" ); + m_ungroupObjects = new KAction( + i18n( "&Ungroup Objects" ), "ungroup", QKeySequence( "Ctrl+Shift+G" ), this, + SLOT( ungroupSelection() ), actionCollection(), "selection_ungroup" ); + m_closePath = new KAction( + i18n( "&Close Path" ), QKeySequence( "Ctrl+U" ), this, + SLOT( closePath() ), actionCollection(), "close_path" ); + // object <----- + + // line style (dashes) + m_lineStyleAction = new KoLineStyleAction( i18n( "Line Style" ), "linestyle", this, SLOT( setLineStyle( int ) ), actionCollection(), "setLineStyle" ); + + // line width + m_setLineWidth = new KoUnitDoubleSpinComboBox( this, 0.0, 1000.0, 0.5, 1.0, KoUnit::U_PT, 1 ); + new KWidgetAction( m_setLineWidth, i18n( "Set Line Width" ), 0, this, SLOT( setLineWidth() ), actionCollection(), "setLineWidth" ); + m_setLineWidth->insertItem( 0.25 ); + m_setLineWidth->insertItem( 0.5 ); + m_setLineWidth->insertItem( 0.75 ); + m_setLineWidth->insertItem( 1.0 ); + m_setLineWidth->insertItem( 2.0 ); + m_setLineWidth->insertItem( 3.0 ); + m_setLineWidth->insertItem( 4.0 ); + m_setLineWidth->insertItem( 5.0 ); + m_setLineWidth->insertItem( 10.0 ); + m_setLineWidth->insertItem( 20.0 ); + connect( m_setLineWidth, SIGNAL( valueChanged( double ) ), this, SLOT( setLineWidth() ) ); + + m_configureAction = new KAction( + i18n( "Configure Karbon..." ), "configure", 0, this, + SLOT( configure() ), actionCollection(), "configure" ); + + new KAction( i18n( "Page &Layout..." ), 0, this, + SLOT( pageLayout() ), actionCollection(), "page_layout" ); + m_contextHelpAction = new KoContextHelpAction( actionCollection(), this ); +} + +void +KarbonView::paintEverything( QPainter& /*p*/, const QRect& /*rect*/, bool /*transparent*/ ) +{ + kdDebug(38000) << "view->paintEverything()" << endl; +} + +bool +KarbonView::mouseEvent( QMouseEvent* event, const KoPoint &p ) +{ + int mx = event->pos().x(); + int my = event->pos().y(); + + int px; + int py; + if( m_canvas->horizontalScrollBar()->isVisible() && ((m_canvas->horizontalScrollBar()->value() - m_canvas->pageOffsetX()) > 0)) + px = mx; + else + px = (mx + canvasWidget()->contentsX() - canvasWidget()->pageOffsetX()); + + if( m_canvas->verticalScrollBar()->isVisible() && ((m_canvas->verticalScrollBar()->value() - m_canvas->pageOffsetY()) > 0)) + py = my; + else + py = (my + canvasWidget()->contentsY() - canvasWidget()->pageOffsetY()); + + m_horizRuler->updatePointer(px, py); + m_vertRuler->updatePointer(px, py); + + KoPoint xy; + xy.setX((mx + canvasWidget()->contentsX() - canvasWidget()->pageOffsetX())/zoom()); + xy.setY( qRound(m_part->document().height()) - (my + canvasWidget()->contentsY() - canvasWidget()->pageOffsetY())/zoom()); + + xy.setX(KoUnit::toUserValue(xy.x(), part()->unit())); + xy.setY(KoUnit::toUserValue(xy.y(), part()->unit())); + + m_cursorCoords->setText( QString( "%1, %2" ).arg(KGlobal::_locale->formatNumber(xy.x(), 2)).arg(KGlobal::_locale->formatNumber(xy.y(), 2)) ); + + if( toolController() ) + return toolController()->mouseEvent( event, p ); + else + return false; +} + +bool +KarbonView::keyEvent( QEvent* event ) +{ + if( toolController() ) + return toolController()->keyEvent( event ); + else + return false; +} + +void +KarbonView::reorganizeGUI() +{ + if( statusBar() ) + { + if( part()->showStatusBar() ) + statusBar()->show(); + else + statusBar()->hide(); + } +} + +void +KarbonView::setNumberOfRecentFiles( unsigned int number ) +{ + if( shell() ) // 0L when embedded into konq ! + shell()->setMaxRecentItems( number ); +} + +void +KarbonView::showRuler() +{ + if( shell() && m_showRulerAction->isChecked() ) + { + m_horizRuler->show(); + m_vertRuler->show(); + m_canvas->setGeometry( rulerWidth, rulerHeight, width() - rulerWidth, height() - rulerHeight ); + updateRuler(); + } + else + { + m_horizRuler->hide(); + m_vertRuler->hide(); + m_canvas->setGeometry( 0, 0, width(), height() ); + } + + zoomChanged(); +} + +bool +KarbonView::showPageMargins() +{ + return ((KToggleAction*)actionCollection()->action("view_show_margins"))->isChecked(); +} + +void +KarbonView::togglePageMargins(bool b) +{ + ((KToggleAction*)actionCollection()->action("view_show_margins"))->setChecked(b); + m_canvas->repaintAll(); +} + +void +KarbonView::updateRuler() +{ + if(!m_canvas->horizontalScrollBar()->isVisible()) + { + if( (1 + m_canvas->pageOffsetX() - m_canvas->contentsX()) >= 0 ) + { + m_horizRuler->setGeometry( 1 + rulerWidth + m_canvas->pageOffsetX() - m_canvas->contentsX(), 0, qRound( 1 + part()->document().width() * zoom() ), rulerHeight ); + m_horizRuler->updateVisibleArea(0,0); + } + else + { + m_horizRuler->setGeometry( rulerWidth, 0, qRound( 1 + part()->document().width() * zoom() ) - m_canvas->contentsX() + m_canvas->pageOffsetX(), rulerHeight ); + m_horizRuler->updateVisibleArea((m_canvas->contentsX() - m_canvas->pageOffsetX()),0); + } + } + + if(!m_canvas->verticalScrollBar()->isVisible()) + { + if( (1 + m_canvas->pageOffsetY() - m_canvas->contentsY()) >= 0 ) + { + m_vertRuler->setGeometry( 0, 1 + rulerHeight + m_canvas->pageOffsetY() - m_canvas->contentsY(), rulerWidth, 1 + qRound( part()->document().height() * zoom() )); + m_vertRuler->updateVisibleArea(0,0); + } + else + { + m_vertRuler->setGeometry( 0, 1 + rulerHeight, rulerWidth, 1 + qRound( part()->document().height() * zoom() ) + m_canvas->contentsY() - m_canvas->pageOffsetY() ); + m_vertRuler->updateVisibleArea(0, (m_canvas->contentsY() - m_canvas->pageOffsetY())); + } + } +} + +void +KarbonView::showGrid() +{ + m_part->document().grid().isShow = m_showGridAction->isChecked(); +} + +void +KarbonView::snapToGrid() +{ + m_part->document().grid().isSnap = m_snapGridAction->isChecked(); +} + +void +KarbonView::showSelectionPopupMenu( const QPoint &pos ) +{ + QPtrList<KAction> actionList; + if( m_groupObjects->isEnabled() ) + actionList.append( m_groupObjects ); + else if( m_ungroupObjects->isEnabled() ) + actionList.append( m_ungroupObjects ); + if( m_closePath->isEnabled() ) + actionList.append( m_closePath ); + plugActionList( "selection_type_action", actionList ); + ((QPopupMenu *)factory()->container( "selection_popup", this ) )->exec( pos ); + unplugActionList( "selection_type_action" ); +} + +void +KarbonView::configure() +{ + VConfigureDlg dialog( this ); + dialog.exec(); +} + +void +KarbonView::pageLayout() +{ + KoHeadFoot hf; + KoPageLayout layout = part()->pageLayout(); + KoUnit::Unit unit = part()->unit(); + if( KoPageLayoutDia::pageLayout( layout, hf, FORMAT_AND_BORDERS | DISABLE_UNIT, unit ) ) + { + part()->setPageLayout( layout, unit ); + m_horizRuler->setUnit( unit ); + m_vertRuler->setUnit( unit ); + m_canvas->resizeContents( int( ( part()->pageLayout().ptWidth + 300 ) * zoom() ), + int( ( part()->pageLayout().ptHeight + 460 ) * zoom() ) ); + part()->repaintAllViews(); + + emit pageLayoutChanged(); + } +} + +void +KarbonView::canvasContentsMoving( int x, int y ) +{ + if( m_canvas->horizontalScrollBar()->isVisible() ) + { + if( shell() && m_showRulerAction->isChecked() ) + { + if( (1 + m_canvas->pageOffsetX() - x) >= 0) + { + m_horizRuler->setGeometry( 1 + rulerWidth + m_canvas->pageOffsetX() - x, 0, qRound( 1 + part()->document().width() * zoom() ), rulerHeight ); + m_horizRuler->updateVisibleArea(0,0); + } + else + { + m_horizRuler->setGeometry( rulerWidth, 0, qRound( 1 + part()->document().width() * zoom() ) - x + m_canvas->pageOffsetX(), rulerHeight ); + m_horizRuler->updateVisibleArea((x - m_canvas->pageOffsetX()),0); + } + } + } + + if( m_canvas->verticalScrollBar()->isVisible() ) + { + if( shell() && m_showRulerAction->isChecked() ) + { + if( (1 + m_canvas->pageOffsetY() - y) >= 0) + { + m_vertRuler->setGeometry( 0, 1 + rulerHeight + m_canvas->pageOffsetY() - y , rulerWidth, 1 + qRound( part()->document().height() * zoom() )); + m_vertRuler->updateVisibleArea(0,0); + } + else + { + m_vertRuler->setGeometry( 0, 1 + rulerHeight, rulerWidth, 1 + qRound( part()->document().height() * zoom() ) - y + m_canvas->pageOffsetY() ); + m_vertRuler->updateVisibleArea(0, (y - m_canvas->pageOffsetY())); + } + } + } +} + +void +KarbonView::selectionChanged() +{ + VSelection *selection = part()->document().selection(); + int count = selection->objects().count(); + m_groupObjects->setEnabled( false ); + m_closePath->setEnabled( false ); + m_ungroupObjects->setEnabled( false ); + + if( count > 0 ) + { + VObject *obj = selection->objects().getFirst(); + VFill fill = obj->fill() ? *obj->fill() : VFill(); + VStroke stroke = obj->stroke() ? *obj->stroke() : VStroke(); + + if ( shell() ) { + //if ( this == shell()->rootView() || koDocument()->isEmbedded() ) { + m_strokeFillPreview->update( stroke, fill ); + m_smallPreview->update( stroke, fill ); + //} + } + m_strokeDocker->setStroke( stroke ); + + if( count == 1 ) + { + VGroup *group = dynamic_cast<VGroup *>( selection->objects().getFirst() ); + m_ungroupObjects->setEnabled( group ); + VPath *path = dynamic_cast<VPath *>( selection->objects().getFirst() ); + m_closePath->setEnabled( path && !path->isClosed() ); + } + else + m_groupObjects->setEnabled( true ); + + selection->setStroke( stroke ); + selection->setFill( fill ); + m_setLineWidth->setEnabled( true ); + m_setLineWidth->updateValue( stroke.lineWidth() ); + // dashes + m_lineStyleAction->setEnabled( true ); + if( stroke.dashPattern().array().isEmpty() ) + m_lineStyleAction->setCurrentSelection( Qt::SolidLine ); + else if( stroke.dashPattern().array()[ 0 ] == 0. ) + m_lineStyleAction->setCurrentSelection( Qt::NoPen ); + else if( stroke.dashPattern().array()[ 0 ] == 2. ) + m_lineStyleAction->setCurrentSelection( Qt::DotLine ); + else if( stroke.dashPattern().array().count() == 2 ) + m_lineStyleAction->setCurrentSelection( Qt::DashLine ); + else if( stroke.dashPattern().array().count() == 4 ) + m_lineStyleAction->setCurrentSelection( Qt::DashDotLine ); + else if( stroke.dashPattern().array().count() == 6 ) + m_lineStyleAction->setCurrentSelection( Qt::DashDotDotLine ); + + m_deleteSelectionAction->setEnabled( true ); + } + else + { + if ( shell() ) + { + VFill fill = selection->fill() ? *selection->fill() : VFill(); + VStroke stroke = selection->stroke() ? *selection->stroke() : VStroke(); + //if ( this == shell()->rootView() || koDocument()->isEmbedded() && m_strokeFillPreview ) + m_strokeFillPreview->update( stroke, fill ); + } + m_lineStyleAction->setEnabled( false ); + m_deleteSelectionAction->setEnabled( false ); + } + emit selectionChange(); +} +void +KarbonView::setCursor( const QCursor &c ) +{ + m_canvas->setCursor( c ); +} + +void +KarbonView::repaintAll( const KoRect &r ) +{ + m_canvas->repaintAll( r ); +} + +void +KarbonView::repaintAll( bool repaint ) +{ + m_canvas->repaintAll( repaint ); +} +void +KarbonView::setPos( const KoPoint& p ) +{ + m_canvas->setPos( p ); +} + +void +KarbonView::setViewportRect( const KoRect &rect ) +{ + m_canvas->setViewportRect( rect ); +} + +void +KarbonView::setUnit( KoUnit::Unit /*_unit*/ ) +{ +} + +void KarbonView::createDocumentTabDock() +{ + m_DocumentTab = new VDocumentTab(this, this); + m_DocumentTab->setCaption(i18n("Document")); + paletteManager()->addWidget(m_DocumentTab, "DocumentTabDock", "DocumentPanel"); + connect( m_part, SIGNAL( unitChanged( KoUnit::Unit ) ), m_DocumentTab, SLOT( updateDocumentInfo() ) ); +} + +void KarbonView::createLayersTabDock() +{ + m_LayersTab = new VLayersTab(this, this); + m_LayersTab->setCaption(i18n("Layers")); + paletteManager()->addWidget(m_LayersTab, "LayersTabDock", "DocumentPanel"); +} + +void KarbonView::createHistoryTabDock() +{ + m_HistoryTab = new VHistoryTab(part(), this); + m_HistoryTab->setCaption(i18n("History")); + paletteManager()->addWidget(m_HistoryTab, "HistoryTabDock", "DocumentPanel"); +} + +void KarbonView::createStrokeDock() +{ + m_strokeDocker = new VStrokeDocker(part(), this); + m_strokeDocker->setCaption(i18n("Stroke Properties")); + paletteManager()->addWidget(m_strokeDocker, "StrokeTabDock", "StrokePanel"); + + connect( part(), SIGNAL( unitChanged( KoUnit::Unit ) ), m_strokeDocker, SLOT( setUnit( KoUnit::Unit ) ) ); +} + +void KarbonView::createColorDock() +{ + m_ColorManager = new VColorDocker(part(),this); + //m_ColorManager->setCaption(i18n("Stroke Properties")); + paletteManager()->addWidget(m_ColorManager, "ColorTabDock", "ColorPanel"); + + connect( this, SIGNAL( selectionChange() ), m_ColorManager, SLOT( update() ) ); +} + +void KarbonView::createTransformDock() +{ + m_TransformDocker = new VTransformDocker(part(), this); + m_TransformDocker->setCaption(i18n("Transform")); + paletteManager()->addWidget(m_TransformDocker, "TransformTabDock", "TransformPanel"); + + connect( this, SIGNAL( selectionChange() ), m_TransformDocker, SLOT( update() ) ); + connect( part(), SIGNAL( unitChanged( KoUnit::Unit ) ), m_TransformDocker, SLOT( setUnit( KoUnit::Unit ) ) ); +} + +void KarbonView::createResourceDock() +{ + m_styleDocker = new VStyleDocker( part(), this ); + m_styleDocker->setCaption(i18n("Resources")); + paletteManager()->addWidget(m_styleDocker, "ResourceTabDock", "ResourcePanel"); +} + +VToolController * +KarbonView::toolController() +{ + return m_toolController; +} + +void KarbonView::commandExecuted( VCommand *command ) +{ + if( command && command->changesSelection() ) + selectionChanged(); +} + +void KarbonView::strokeFillSelectionChanged( KDualColorButton::DualColor s ) +{ + if( s == KDualColorButton::Foreground ) + m_strokeFillPreview->setStrokeSelected(); + else + m_strokeFillPreview->setFillSelected(); + selectionChanged(); +} + +void KarbonView::colorChanged( const QColor &c ) +{ + selectionChanged(); +} + +#include "karbon_view.moc" + diff --git a/karbon/karbon_view.h b/karbon/karbon_view.h new file mode 100644 index 00000000..2e1e4dc0 --- /dev/null +++ b/karbon/karbon_view.h @@ -0,0 +1,284 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBON_VIEW__ +#define __KARBON_VIEW__ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <KoView.h> +#include <KoPoint.h> +#include <ksharedptr.h> +#include <kxmlguibuilder.h> +#include <kdualcolorbutton.h> +#include <KoUnit.h> +#include <koffice_export.h> +class DCOPObject; +class QLabel; + +class KAction; +class KarbonPart; +class KSelectAction; +class KToggleAction; +class KoContextHelpAction; +class KoLineStyleAction; + +class KoUnitDoubleSpinComboBox; +class KoRect; +class VRuler; + +class KoPaletteManager; +class VDocumentTab; +class VLayersTab; +class VHistoryTab; +class VStrokeDocker; +class VColorDocker; +class VStyleDocker; +class VTransformDocker; + +class VFill; +class VPainterFactory; +class VSelectToolBar; +class VSmallPreview; +class VStateButton; +class VStroke; +class VStrokeFillPreview; +class VCanvas; +class VStrokeFillPreview; +class VTypeButtonBox; + +class VTool; +class VToolBox; +class VToolController; + +class VCommand; + +class KARBONCOMMON_EXPORT KarbonView : public KoView, public KXMLGUIBuilder +{ + Q_OBJECT + +public: + KarbonView( KarbonPart* part, QWidget* parent = 0L, + const char* name = 0L ); + virtual ~KarbonView(); + + virtual DCOPObject* dcopObject(); + + KarbonPart *part() const { return m_part; } + + virtual void paintEverything( QPainter &p, const QRect &rect, bool transparent = false ); + + bool mouseEvent( QMouseEvent* event, const KoPoint & ); + bool keyEvent( QEvent* event ); + void dropEvent( QDropEvent *e ); + + virtual QWidget* canvas() const; + + VCanvas* canvasWidget() const { return m_canvas; } + + virtual VPainterFactory* painterFactory() const { return m_painterFactory; } + + KoPaletteManager* paletteManager() { return m_pPaletteManager; }; + + // printing support, override from KoView + virtual void setupPrinter( KPrinter &/*printer*/ ) {} + virtual void print( KPrinter& printer ); + + KoContextHelpAction* contextHelpAction() const { return m_contextHelpAction; } + + void reorganizeGUI(); + void setNumberOfRecentFiles( unsigned int number ); + void setLineWidth( double val ); + + QLabel* statusMessage() const { return m_status; } + + void setCursor( const QCursor & ); + + void repaintAll( const KoRect & ); + void repaintAll( bool = true ); + + void setPos( const KoPoint& p ); + + void setViewportRect( const KoRect &rect ); + void setZoomAt( double zoom, const KoPoint & = KoPoint() ); + + VToolController *toolController(); + + VStrokeFillPreview* strokeFillPreview() + { return m_strokeFillPreview; } + +public slots: + // editing: + void editCut(); + void editCopy(); + void editPaste(); + void editSelectAll(); + void editDeselectAll(); + void editDeleteSelection(); + void editPurgeHistory(); + + void selectionDuplicate(); + void selectionBringToFront(); + void selectionSendToBack(); + void selectionMoveUp(); + void selectionMoveDown(); + void selectionAlignHorizontalLeft(); + void selectionAlignHorizontalCenter(); + void selectionAlignHorizontalRight(); + void selectionAlignVerticalTop(); + void selectionAlignVerticalCenter(); + void selectionAlignVerticalBottom(); + + void selectionDistributeHorizontalCenter(); + void selectionDistributeHorizontalGap(); + void selectionDistributeHorizontalLeft(); + void selectionDistributeHorizontalRight(); + void selectionDistributeVerticalCenter(); + void selectionDistributeVerticalGap(); + void selectionDistributeVerticalBottom(); + void selectionDistributeVerticalTop(); + + void fileImportGraphic(); + + void groupSelection(); + void ungroupSelection(); + + void closePath(); + + //View: + void viewZoomIn(); + void viewZoomOut(); + + void setUnit( KoUnit::Unit _unit ); + + void configure(); + + void pageLayout(); + + void setLineWidth(); + void selectionChanged(); + + void slotActiveToolChanged( VTool * ); + + void togglePageMargins(bool); + void showRuler(); + void showGrid(); + bool showPageMargins(); + void snapToGrid(); + + void showSelectionPopupMenu( const QPoint &pos ); + +protected slots: + // Object related operations. + + // View. + void viewModeChanged(); + void zoomChanged( const KoPoint & = KoPoint() ); + void setLineStyle( int ); + + // Toolbox dialogs. + void slotStrokeChanged( const VStroke& ); + void slotFillChanged( const VFill & ); + + void canvasContentsMoving( int x, int y ); + void commandExecuted( VCommand *command ); + void strokeFillSelectionChanged( KDualColorButton::DualColor s ); + void colorChanged( const QColor &c ); +signals: + void zoomChanged( double ); + void selectionChange(); + void pageLayoutChanged(); + +protected: + virtual void updateReadWrite( bool ) {} + virtual void resizeEvent( QResizeEvent* event ); + + void createDocumentTabDock(); + void createLayersTabDock(); + void createHistoryTabDock(); + void createStrokeDock(); + void createColorDock(); + void createTransformDock(); + void createResourceDock(); + + //KXMLGUIBuilder + virtual QWidget *createContainer( QWidget *parent, int index, const QDomElement &element, int &id ); + virtual void removeContainer( QWidget *container, QWidget *parent, QDomElement &element, int id ); + void addSelectionToClipboard() const; + +private: + void initActions(); + void updateRuler(); + + KarbonPart *m_part; + VCanvas *m_canvas; + VRuler *m_horizRuler; + VRuler *m_vertRuler; + + VPainterFactory *m_painterFactory; + VStrokeFillPreview *m_strokeFillPreview; + VTypeButtonBox *m_typeButtonBox; + + VToolBox *m_toolbox; + + KAction *m_groupObjects; + KAction *m_ungroupObjects; + + KAction *m_closePath; + + // actions: + KSelectAction *m_zoomAction; + KSelectAction *m_viewAction; + KAction *m_configureAction; + KToggleAction *m_showRulerAction; + KToggleAction *m_showGridAction; + KToggleAction *m_snapGridAction; + KToggleAction *m_showPageMargins; + KoContextHelpAction *m_contextHelpAction; + KAction *m_deleteSelectionAction; + // line width + KoUnitDoubleSpinComboBox *m_setLineWidth; + KoLineStyleAction *m_lineStyleAction; + + //dockers + KoPaletteManager *m_pPaletteManager; + VDocumentTab *m_DocumentTab; + VLayersTab *m_LayersTab; + VHistoryTab *m_HistoryTab; + VColorDocker *m_ColorManager; + VStrokeDocker *m_strokeDocker; + VStyleDocker *m_styleDocker; + VTransformDocker *m_TransformDocker; + + VSelectToolBar *m_selectToolBar; + + // dcop + DCOPObject *m_dcop; + + //Status Bar + QLabel *m_status; // Ordinary status + QLabel *m_cursorCoords; // Cursor coordinates + VSmallPreview *m_smallPreview; // Stroke and Fill + VToolController *m_toolController; +}; + +#endif + diff --git a/karbon/karbon_view_iface.cc b/karbon/karbon_view_iface.cc new file mode 100644 index 00000000..3fdf1778 --- /dev/null +++ b/karbon/karbon_view_iface.cc @@ -0,0 +1,150 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <dcopclient.h> + +#include "karbon_view.h" +#include "karbon_view_iface.h" +#include "vcanvas.h" + +KarbonViewIface::KarbonViewIface( KarbonView* view ) + : KoViewIface( view ) +{ + m_view = view; +} + +void +KarbonViewIface::editCut() +{ + m_view->editCut(); +} + +void +KarbonViewIface::editCopy() +{ + m_view->editCopy(); +} + +void +KarbonViewIface::editPaste() +{ + m_view->editPaste(); +} + +void +KarbonViewIface::editSelectAll() +{ + m_view->editSelectAll(); +} + +void +KarbonViewIface::editDeselectAll() +{ + m_view->editDeselectAll(); +} + +void +KarbonViewIface::editDeleteSelection() +{ + m_view->editDeleteSelection(); +} + +void +KarbonViewIface::editPurgeHistory() +{ + m_view->editPurgeHistory(); +} + +void +KarbonViewIface::objectMoveToTop() +{ + m_view->selectionBringToFront(); +} + +void +KarbonViewIface::objectMoveToBottom() +{ + m_view->selectionSendToBack(); +} + +void +KarbonViewIface::objectMoveUp() +{ + m_view->selectionMoveUp(); +} + +void +KarbonViewIface::objectMoveDown() +{ + m_view->selectionMoveDown(); +} + +double +KarbonViewIface::zoomFactor() const +{ + return m_view->zoom(); +} + +void KarbonViewIface::groupSelection() +{ + m_view->groupSelection(); +} + +void KarbonViewIface::ungroupSelection() +{ + m_view->ungroupSelection(); +} + +void KarbonViewIface::configure() +{ + m_view->configure(); +} + +void KarbonViewIface::setLineWidth( double val ) +{ + m_view->setLineWidth( val ); +} + + +void KarbonViewIface::insertKnots() +{ + //m_view->pathInsertKnots(); +} + +void KarbonViewIface::pathFlatten() +{ + //m_view->pathFlatten(); +} + +void KarbonViewIface::pathRoundCorners() +{ + //m_view->pathRoundCorners(); +} + +void KarbonViewIface::pathWhirlPinch() +{ + //m_view->pathWhirlPinch(); +} + +void KarbonViewIface::repaint() +{ + m_view->canvasWidget()->repaintAll(); +} + diff --git a/karbon/karbon_view_iface.h b/karbon/karbon_view_iface.h new file mode 100644 index 00000000..bacfe3f4 --- /dev/null +++ b/karbon/karbon_view_iface.h @@ -0,0 +1,71 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __KARBON_VIEW_IFACE_H__ +#define __KARBON_VIEW_IFACE_H__ + + +#include <qstring.h> + +#include <KoViewIface.h> + +class KarbonView; + + +class KarbonViewIface : public KoViewIface +{ + K_DCOP + +public: + KarbonViewIface( KarbonView* view ); + +k_dcop: + void editCut(); + void editCopy(); + void editPaste(); + void editSelectAll(); + void editDeselectAll(); + void editDeleteSelection(); + void editPurgeHistory(); + + void objectMoveToTop(); + void objectMoveToBottom(); + void objectMoveUp(); + void objectMoveDown(); + + double zoomFactor() const; + + void groupSelection(); + void ungroupSelection(); + void configure(); + void setLineWidth( double val ); + + void insertKnots(); + void pathFlatten(); + void pathRoundCorners(); + void pathWhirlPinch(); + + void repaint(); + +private: + KarbonView* m_view; +}; + +#endif + diff --git a/karbon/main.cc b/karbon/main.cc new file mode 100644 index 00000000..edd929c3 --- /dev/null +++ b/karbon/main.cc @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <dcopclient.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <KoApplication.h> + +#include "karbon_aboutdata.h" + + +static const KCmdLineOptions options[] = + { + { "+[file]", I18N_NOOP( "File to open" ), 0 } , + KCmdLineLastOption + }; + +extern "C" KARBONBASE_EXPORT int kdemain( int argc, char* argv[] ) +{ + KCmdLineArgs::init( argc, argv, newKarbonAboutData() ); + KCmdLineArgs::addCmdLineOptions( options ); + KoApplication app; + + if( !app.start() ) // parses command line args, create initial docs and shells + return 1; + + return app.exec(); +} + diff --git a/karbon/pics/Makefile.am b/karbon/pics/Makefile.am new file mode 100644 index 00000000..3cfd3303 --- /dev/null +++ b/karbon/pics/Makefile.am @@ -0,0 +1,4 @@ +karbonicondir = $(kde_datadir)/karbon/icons +karbonicon_ICON = AUTO + +KDE_ICON = karbon diff --git a/karbon/pics/cr16-action-14_layer_deletelayer.png b/karbon/pics/cr16-action-14_layer_deletelayer.png Binary files differnew file mode 100644 index 00000000..9883939c --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_deletelayer.png diff --git a/karbon/pics/cr16-action-14_layer_lowerlayer.png b/karbon/pics/cr16-action-14_layer_lowerlayer.png Binary files differnew file mode 100644 index 00000000..36de3383 --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_lowerlayer.png diff --git a/karbon/pics/cr16-action-14_layer_newlayer.png b/karbon/pics/cr16-action-14_layer_newlayer.png Binary files differnew file mode 100644 index 00000000..d4736bb9 --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_newlayer.png diff --git a/karbon/pics/cr16-action-14_layer_novisible.png b/karbon/pics/cr16-action-14_layer_novisible.png Binary files differnew file mode 100644 index 00000000..43cbf789 --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_novisible.png diff --git a/karbon/pics/cr16-action-14_layer_raiselayer.png b/karbon/pics/cr16-action-14_layer_raiselayer.png Binary files differnew file mode 100644 index 00000000..e97cd597 --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_raiselayer.png diff --git a/karbon/pics/cr16-action-14_layer_visible.png b/karbon/pics/cr16-action-14_layer_visible.png Binary files differnew file mode 100644 index 00000000..457b7210 --- /dev/null +++ b/karbon/pics/cr16-action-14_layer_visible.png diff --git a/karbon/pics/cr16-action-14_pencil.png b/karbon/pics/cr16-action-14_pencil.png Binary files differnew file mode 100644 index 00000000..592a0b10 --- /dev/null +++ b/karbon/pics/cr16-action-14_pencil.png diff --git a/karbon/pics/cr16-action-cap_butt.png b/karbon/pics/cr16-action-cap_butt.png Binary files differnew file mode 100644 index 00000000..56acddf6 --- /dev/null +++ b/karbon/pics/cr16-action-cap_butt.png diff --git a/karbon/pics/cr16-action-cap_round.png b/karbon/pics/cr16-action-cap_round.png Binary files differnew file mode 100644 index 00000000..f664a060 --- /dev/null +++ b/karbon/pics/cr16-action-cap_round.png diff --git a/karbon/pics/cr16-action-cap_square.png b/karbon/pics/cr16-action-cap_square.png Binary files differnew file mode 100644 index 00000000..a7a21f63 --- /dev/null +++ b/karbon/pics/cr16-action-cap_square.png diff --git a/karbon/pics/cr16-action-colorman.png b/karbon/pics/cr16-action-colorman.png Binary files differnew file mode 100644 index 00000000..e03a65a4 --- /dev/null +++ b/karbon/pics/cr16-action-colorman.png diff --git a/karbon/pics/cr16-action-helpdocker.png b/karbon/pics/cr16-action-helpdocker.png Binary files differnew file mode 100644 index 00000000..687d8388 --- /dev/null +++ b/karbon/pics/cr16-action-helpdocker.png diff --git a/karbon/pics/cr16-action-historydocker.png b/karbon/pics/cr16-action-historydocker.png Binary files differnew file mode 100644 index 00000000..93a445ce --- /dev/null +++ b/karbon/pics/cr16-action-historydocker.png diff --git a/karbon/pics/cr16-action-join_bevel.png b/karbon/pics/cr16-action-join_bevel.png Binary files differnew file mode 100644 index 00000000..13fe979c --- /dev/null +++ b/karbon/pics/cr16-action-join_bevel.png diff --git a/karbon/pics/cr16-action-join_miter.png b/karbon/pics/cr16-action-join_miter.png Binary files differnew file mode 100644 index 00000000..65724adc --- /dev/null +++ b/karbon/pics/cr16-action-join_miter.png diff --git a/karbon/pics/cr16-action-join_round.png b/karbon/pics/cr16-action-join_round.png Binary files differnew file mode 100644 index 00000000..384341e6 --- /dev/null +++ b/karbon/pics/cr16-action-join_round.png diff --git a/karbon/pics/cr16-action-layersman.png b/karbon/pics/cr16-action-layersman.png Binary files differnew file mode 100644 index 00000000..17636114 --- /dev/null +++ b/karbon/pics/cr16-action-layersman.png diff --git a/karbon/pics/cr16-action-locked.png b/karbon/pics/cr16-action-locked.png Binary files differnew file mode 100644 index 00000000..157d034b --- /dev/null +++ b/karbon/pics/cr16-action-locked.png diff --git a/karbon/pics/cr16-action-rotate.png b/karbon/pics/cr16-action-rotate.png Binary files differnew file mode 100644 index 00000000..4388e115 --- /dev/null +++ b/karbon/pics/cr16-action-rotate.png diff --git a/karbon/pics/cr16-action-shear.png b/karbon/pics/cr16-action-shear.png Binary files differnew file mode 100644 index 00000000..fe49e3dc --- /dev/null +++ b/karbon/pics/cr16-action-shear.png diff --git a/karbon/pics/cr16-action-strokedocker.png b/karbon/pics/cr16-action-strokedocker.png Binary files differnew file mode 100644 index 00000000..0cae0604 --- /dev/null +++ b/karbon/pics/cr16-action-strokedocker.png diff --git a/karbon/pics/cr16-action-tooloptions.png b/karbon/pics/cr16-action-tooloptions.png Binary files differnew file mode 100644 index 00000000..91afe762 --- /dev/null +++ b/karbon/pics/cr16-action-tooloptions.png diff --git a/karbon/pics/cr16-action-translate.png b/karbon/pics/cr16-action-translate.png Binary files differnew file mode 100644 index 00000000..a7296c38 --- /dev/null +++ b/karbon/pics/cr16-action-translate.png diff --git a/karbon/pics/cr16-action-unlocked.png b/karbon/pics/cr16-action-unlocked.png Binary files differnew file mode 100644 index 00000000..24428d4c --- /dev/null +++ b/karbon/pics/cr16-action-unlocked.png diff --git a/karbon/pics/cr22-action-14_ellipse.png b/karbon/pics/cr22-action-14_ellipse.png Binary files differnew file mode 100644 index 00000000..5deaf5b1 --- /dev/null +++ b/karbon/pics/cr22-action-14_ellipse.png diff --git a/karbon/pics/cr22-action-14_flatten.png b/karbon/pics/cr22-action-14_flatten.png Binary files differnew file mode 100644 index 00000000..90638199 --- /dev/null +++ b/karbon/pics/cr22-action-14_flatten.png diff --git a/karbon/pics/cr22-action-14_gradient.png b/karbon/pics/cr22-action-14_gradient.png Binary files differnew file mode 100644 index 00000000..72c3eb64 --- /dev/null +++ b/karbon/pics/cr22-action-14_gradient.png diff --git a/karbon/pics/cr22-action-14_image.png b/karbon/pics/cr22-action-14_image.png Binary files differnew file mode 100644 index 00000000..a1f4137e --- /dev/null +++ b/karbon/pics/cr22-action-14_image.png diff --git a/karbon/pics/cr22-action-14_insertknots.png b/karbon/pics/cr22-action-14_insertknots.png Binary files differnew file mode 100644 index 00000000..466a14ba --- /dev/null +++ b/karbon/pics/cr22-action-14_insertknots.png diff --git a/karbon/pics/cr22-action-14_pattern.png b/karbon/pics/cr22-action-14_pattern.png Binary files differnew file mode 100644 index 00000000..fb527498 --- /dev/null +++ b/karbon/pics/cr22-action-14_pattern.png diff --git a/karbon/pics/cr22-action-14_pencil.png b/karbon/pics/cr22-action-14_pencil.png Binary files differnew file mode 100644 index 00000000..3878dc1b --- /dev/null +++ b/karbon/pics/cr22-action-14_pencil.png diff --git a/karbon/pics/cr22-action-14_polygon.png b/karbon/pics/cr22-action-14_polygon.png Binary files differnew file mode 100644 index 00000000..58dcaaa4 --- /dev/null +++ b/karbon/pics/cr22-action-14_polygon.png diff --git a/karbon/pics/cr22-action-14_polyline.png b/karbon/pics/cr22-action-14_polyline.png Binary files differnew file mode 100644 index 00000000..9457a510 --- /dev/null +++ b/karbon/pics/cr22-action-14_polyline.png diff --git a/karbon/pics/cr22-action-14_rectangle.png b/karbon/pics/cr22-action-14_rectangle.png Binary files differnew file mode 100644 index 00000000..d5976c8f --- /dev/null +++ b/karbon/pics/cr22-action-14_rectangle.png diff --git a/karbon/pics/cr22-action-14_rotate.png b/karbon/pics/cr22-action-14_rotate.png Binary files differnew file mode 100644 index 00000000..6d137285 --- /dev/null +++ b/karbon/pics/cr22-action-14_rotate.png diff --git a/karbon/pics/cr22-action-14_roundcorners.png b/karbon/pics/cr22-action-14_roundcorners.png Binary files differnew file mode 100644 index 00000000..082edf88 --- /dev/null +++ b/karbon/pics/cr22-action-14_roundcorners.png diff --git a/karbon/pics/cr22-action-14_roundrect.png b/karbon/pics/cr22-action-14_roundrect.png Binary files differnew file mode 100644 index 00000000..d9aa00f3 --- /dev/null +++ b/karbon/pics/cr22-action-14_roundrect.png diff --git a/karbon/pics/cr22-action-14_select.png b/karbon/pics/cr22-action-14_select.png Binary files differnew file mode 100644 index 00000000..800cb920 --- /dev/null +++ b/karbon/pics/cr22-action-14_select.png diff --git a/karbon/pics/cr22-action-14_selectnodes.png b/karbon/pics/cr22-action-14_selectnodes.png Binary files differnew file mode 100644 index 00000000..be4c20dc --- /dev/null +++ b/karbon/pics/cr22-action-14_selectnodes.png diff --git a/karbon/pics/cr22-action-14_shear.png b/karbon/pics/cr22-action-14_shear.png Binary files differnew file mode 100644 index 00000000..019fe746 --- /dev/null +++ b/karbon/pics/cr22-action-14_shear.png diff --git a/karbon/pics/cr22-action-14_sinus.png b/karbon/pics/cr22-action-14_sinus.png Binary files differnew file mode 100644 index 00000000..14ac3ba6 --- /dev/null +++ b/karbon/pics/cr22-action-14_sinus.png diff --git a/karbon/pics/cr22-action-14_spiral.png b/karbon/pics/cr22-action-14_spiral.png Binary files differnew file mode 100644 index 00000000..b05c30e1 --- /dev/null +++ b/karbon/pics/cr22-action-14_spiral.png diff --git a/karbon/pics/cr22-action-14_star.png b/karbon/pics/cr22-action-14_star.png Binary files differnew file mode 100644 index 00000000..77e9579b --- /dev/null +++ b/karbon/pics/cr22-action-14_star.png diff --git a/karbon/pics/cr22-action-14_text.png b/karbon/pics/cr22-action-14_text.png Binary files differnew file mode 100644 index 00000000..e5642cdd --- /dev/null +++ b/karbon/pics/cr22-action-14_text.png diff --git a/karbon/pics/cr22-action-14_whirl.png b/karbon/pics/cr22-action-14_whirl.png Binary files differnew file mode 100644 index 00000000..95673e0e --- /dev/null +++ b/karbon/pics/cr22-action-14_whirl.png diff --git a/karbon/pics/cr22-action-14_zoom.png b/karbon/pics/cr22-action-14_zoom.png Binary files differnew file mode 100644 index 00000000..e726162c --- /dev/null +++ b/karbon/pics/cr22-action-14_zoom.png diff --git a/karbon/pics/cr22-action-colorman.png b/karbon/pics/cr22-action-colorman.png Binary files differnew file mode 100644 index 00000000..2a9ab92c --- /dev/null +++ b/karbon/pics/cr22-action-colorman.png diff --git a/karbon/pics/cr22-action-gradientdlg.png b/karbon/pics/cr22-action-gradientdlg.png Binary files differnew file mode 100644 index 00000000..156f93c1 --- /dev/null +++ b/karbon/pics/cr22-action-gradientdlg.png diff --git a/karbon/pics/cr22-action-outlinedlg.png b/karbon/pics/cr22-action-outlinedlg.png Binary files differnew file mode 100644 index 00000000..dc70c08e --- /dev/null +++ b/karbon/pics/cr22-action-outlinedlg.png diff --git a/karbon/pics/cr22-action-pagesetup.png b/karbon/pics/cr22-action-pagesetup.png Binary files differnew file mode 100644 index 00000000..8e4cb740 --- /dev/null +++ b/karbon/pics/cr22-action-pagesetup.png diff --git a/karbon/pics/cr22-action-solidfilldlg.png b/karbon/pics/cr22-action-solidfilldlg.png Binary files differnew file mode 100644 index 00000000..acad8c7f --- /dev/null +++ b/karbon/pics/cr22-action-solidfilldlg.png diff --git a/karbon/pics/hi16-action-linestyle.png b/karbon/pics/hi16-action-linestyle.png Binary files differnew file mode 100644 index 00000000..ed9b0eeb --- /dev/null +++ b/karbon/pics/hi16-action-linestyle.png diff --git a/karbon/pics/hi16-app-karbon.png b/karbon/pics/hi16-app-karbon.png Binary files differnew file mode 100644 index 00000000..9351909c --- /dev/null +++ b/karbon/pics/hi16-app-karbon.png diff --git a/karbon/pics/hi22-action-linestyle.png b/karbon/pics/hi22-action-linestyle.png Binary files differnew file mode 100644 index 00000000..f96e1dc7 --- /dev/null +++ b/karbon/pics/hi22-action-linestyle.png diff --git a/karbon/pics/hi22-app-karbon.png b/karbon/pics/hi22-app-karbon.png Binary files differnew file mode 100644 index 00000000..0dd0195a --- /dev/null +++ b/karbon/pics/hi22-app-karbon.png diff --git a/karbon/pics/hi32-app-karbon.png b/karbon/pics/hi32-app-karbon.png Binary files differnew file mode 100644 index 00000000..e1084e41 --- /dev/null +++ b/karbon/pics/hi32-app-karbon.png diff --git a/karbon/pics/hi48-app-karbon.png b/karbon/pics/hi48-app-karbon.png Binary files differnew file mode 100644 index 00000000..2b3dab28 --- /dev/null +++ b/karbon/pics/hi48-app-karbon.png diff --git a/karbon/pics/hisc-app-karbon.svgz b/karbon/pics/hisc-app-karbon.svgz Binary files differnew file mode 100644 index 00000000..49da8519 --- /dev/null +++ b/karbon/pics/hisc-app-karbon.svgz diff --git a/karbon/plugins/Makefile.am b/karbon/plugins/Makefile.am new file mode 100644 index 00000000..6f43cf6e --- /dev/null +++ b/karbon/plugins/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = flattenpath roundcorners insertknots whirlpinch shadoweffect zoomtool imagetool diff --git a/karbon/plugins/flattenpath/Makefile.am b/karbon/plugins/flattenpath/Makefile.am new file mode 100644 index 00000000..2356e933 --- /dev/null +++ b/karbon/plugins/flattenpath/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_flattenpathplugin.la + +karbon_flattenpathplugin_la_SOURCES = flattenpathplugin.cc +karbon_flattenpathplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KOFFICEUI) \ + ../../libkarboncommon.la + +karbon_flattenpathplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +partpluginsdir = $(kde_datadir)/karbon/kpartplugins +partplugins_DATA = flattenpathplugin.rc + +METASOURCES = AUTO + diff --git a/karbon/plugins/flattenpath/flattenpathplugin.cc b/karbon/plugins/flattenpath/flattenpathplugin.cc new file mode 100644 index 00000000..4532a12c --- /dev/null +++ b/karbon/plugins/flattenpath/flattenpathplugin.cc @@ -0,0 +1,85 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "flattenpathplugin.h" +#include "klocale.h" +#include <karbon_view.h> +#include <karbon_part.h> +#include <kgenericfactory.h> +#include <kdebug.h> +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> +#include <commands/vflattencmd.h> + + +typedef KGenericFactory<FlattenPathPlugin, KarbonView> FlattenPathPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_flattenpathplugin, FlattenPathPluginFactory( "karbonflattenpathplugin" ) ) + +FlattenPathPlugin::FlattenPathPlugin( KarbonView *parent, const char* name, const QStringList & ) +: Plugin( parent, name ) +{ + new KAction( + i18n( "&Flatten Path..." ), "14_flatten", 0, this, + SLOT( slotFlattenPath() ), actionCollection(), "path_flatten" ); + + m_flattenPathDlg = new VFlattenDlg(); + m_flattenPathDlg->setFlatness( 0.2 ); +} + +void +FlattenPathPlugin::slotFlattenPath() +{ + KarbonPart *part = ((KarbonView *)parent())->part(); + if( part && m_flattenPathDlg->exec() ) + part->addCommand( new VFlattenCmd( &part->document(), m_flattenPathDlg->flatness() ), true ); +} + +VFlattenDlg::VFlattenDlg( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Flatten Path" ), Ok | Cancel ) +{ + // add input fields on the left: + QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + new QLabel( i18n( "Flatness:" ), group ); + m_flatness = new KDoubleNumInput( group ); + group->setMinimumWidth( 300 ); + + // signals and slots: + connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +double +VFlattenDlg::flatness() const +{ + return m_flatness->value(); +} + +void +VFlattenDlg::setFlatness( double value ) +{ + m_flatness->setValue( value); +} + +#include "flattenpathplugin.moc" + diff --git a/karbon/plugins/flattenpath/flattenpathplugin.h b/karbon/plugins/flattenpath/flattenpathplugin.h new file mode 100644 index 00000000..0e92d8f3 --- /dev/null +++ b/karbon/plugins/flattenpath/flattenpathplugin.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __FLATTENPATHPLUGIN_H__ +#define __FLATTENPATHPLUGIN_H__ + +#include <kparts/plugin.h> +#include <kdialogbase.h> + +class KarbonView; +class VFlattenDlg; + +class FlattenPathPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + FlattenPathPlugin( KarbonView *parent, const char* name, const QStringList & ); + virtual ~FlattenPathPlugin() {} + +private slots: + void slotFlattenPath(); + +private: + VFlattenDlg *m_flattenPathDlg; +}; + +class KDoubleNumInput; + +class VFlattenDlg : public KDialogBase +{ + Q_OBJECT + +public: + VFlattenDlg( QWidget* parent = 0L, const char* name = 0L ); + + double flatness() const; + void setFlatness( double value ); + +private: + KDoubleNumInput* m_flatness; +}; + +#endif + diff --git a/karbon/plugins/flattenpath/flattenpathplugin.rc b/karbon/plugins/flattenpath/flattenpathplugin.rc new file mode 100644 index 00000000..4b5f76c2 --- /dev/null +++ b/karbon/plugins/flattenpath/flattenpathplugin.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="flattenpathplugin" library="karbon_flattenpathplugin"> +<MenuBar> + <Menu name="effects"> + <Action name="path_flatten"/> + </Menu> +</MenuBar> +<ToolBar name="Effects" hidden="true" fullWidth="false"> + <Action name="path_flatten"/> +</ToolBar> +</kpartplugin> diff --git a/karbon/plugins/imagetool/Makefile.am b/karbon/plugins/imagetool/Makefile.am new file mode 100644 index 00000000..491c0f86 --- /dev/null +++ b/karbon/plugins/imagetool/Makefile.am @@ -0,0 +1,14 @@ +kde_services_DATA = karbonimagetool.desktop + +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_imagetoolplugin.la + +karbon_imagetoolplugin_la_SOURCES = imagetoolplugin.cc vimagetool.cc +karbon_imagetoolplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KOFFICEUI) \ + ../../libkarboncommon.la + +karbon_imagetoolplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +METASOURCES = AUTO + diff --git a/karbon/plugins/imagetool/imagetoolplugin.cc b/karbon/plugins/imagetool/imagetoolplugin.cc new file mode 100644 index 00000000..cd9c7c2f --- /dev/null +++ b/karbon/plugins/imagetool/imagetoolplugin.cc @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <kgenericfactory.h> + +#include "karbon_factory.h" +#include "karbon_tool_factory.h" +#include "karbon_tool_registry.h" + +#include "vimagetool.h" + +#include "imagetoolplugin.h" + +typedef KGenericFactory<ImageToolPlugin> ImageToolPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_imagetoolplugin, ImageToolPluginFactory( "karbonimagetoolplugin" ) ) + +ImageToolPlugin::ImageToolPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(ImageToolPluginFactory::instance()); + + kdDebug() << "VImageToolPlugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if ( parent->inherits("KarbonFactory") ) + { + KarbonToolRegistry* r = KarbonToolRegistry::instance(); + r->add(new KarbonToolFactory<VImageTool>()); + } +} + +ImageToolPlugin::~ImageToolPlugin() +{ +} + +#include "imagetoolplugin.moc" + diff --git a/karbon/plugins/imagetool/imagetoolplugin.h b/karbon/plugins/imagetool/imagetoolplugin.h new file mode 100644 index 00000000..6f7e6547 --- /dev/null +++ b/karbon/plugins/imagetool/imagetoolplugin.h @@ -0,0 +1,39 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __IMAGETOOLPLUGIN_H__ +#define __IMAGETOOLPLUGIN_H__ + +#include <qstring.h> + +#include <kparts/plugin.h> + +/** + */ +class ImageToolPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + ImageToolPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~ImageToolPlugin(); +}; + +#endif + diff --git a/karbon/plugins/imagetool/imagetoolplugin.rc b/karbon/plugins/imagetool/imagetoolplugin.rc new file mode 100644 index 00000000..2defe12d --- /dev/null +++ b/karbon/plugins/imagetool/imagetoolplugin.rc @@ -0,0 +1,3 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="imagetoolplugin" library="karbon_imagetoolplugin"> +</kpartplugin> diff --git a/karbon/plugins/imagetool/karbonimagetool.desktop b/karbon/plugins/imagetool/karbonimagetool.desktop new file mode 100644 index 00000000..1294482e --- /dev/null +++ b/karbon/plugins/imagetool/karbonimagetool.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Image Tool +Name[bg]=Инструмент за изображения +Name[br]=Ostilh skeudenn +Name[ca]=Eina d'imatge +Name[cy]=Erfyn Delwedd +Name[da]=Billedværktøj +Name[de]=Bild-Werkzeug +Name[el]=Εργαλείο εικόνας +Name[eo]=Bildprilaborilo +Name[es]=Herramienta de imagen +Name[et]=Pilditööriist +Name[fa]=ابزار تصویر +Name[fi]=Kuvatyökalu +Name[fr]=Outil d'images +Name[fy]=Ofbyldingsark +Name[ga]=Uirlis Íomhá +Name[gl]=Ferramenta de Imaxes +Name[he]=כלי תמונהב +Name[hr]=Alat za slike +Name[hu]=Képkezelő +Name[is]=Myndatól +Name[it]=Strumento per immagini +Name[ja]=画像ツール +Name[km]=ឧបករណ៍រូបភាព +Name[lv]=Attēlu rīks +Name[nb]=Bildeverktøy +Name[nds]=Bild-Warktüüch +Name[ne]=छवि उपकरण +Name[nl]=Afbeeldingsgereedschap +Name[pl]=Narzędzie do obrazków +Name[pt]=Ferramenta de Imagens +Name[pt_BR]=Ferramenta de Imagens +Name[ru]=Изображение +Name[se]=Govvareaidu +Name[sk]=Nástroj obrázok +Name[sl]=Slikarsko orodje +Name[sr]=Алат за слике +Name[sr@Latn]=Alat za slike +Name[sv]=Bildverktyg +Name[uk]=Засіб для зображень +Name[uz]=Rasm vositasi +Name[uz@cyrillic]=Расм воситаси +Name[zh_CN]=图像工具 +Name[zh_TW]=圖片工具 +ServiceTypes=Karbon/CoreModule +Type=Service +X-KDE-Library=karbon_imagetoolplugin diff --git a/karbon/plugins/imagetool/vimagetool.cc b/karbon/plugins/imagetool/vimagetool.cc new file mode 100644 index 00000000..6511fa4d --- /dev/null +++ b/karbon/plugins/imagetool/vimagetool.cc @@ -0,0 +1,132 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <qcursor.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <kdebug.h> + +#include "vimagetool.h" +#include <karbon_part.h> +#include <karbon_view.h> +#include <core/vimage.h> +#include <core/vselection.h> +#include <core/vcursor.h> + +VImageTool::VImageTool( KarbonView *view ) : VTool( view, "tool_image_plugin" ) +{ + registerTool( this ); + m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) ); +} + +VImageTool::~VImageTool() +{ + delete m_cursor; +} + +QString +VImageTool::contextHelp() +{ + QString s = i18n( "<qt><b>Image tool:</b><br>" ); + return s; +} + +void +VImageTool::activate() +{ + view()->setCursor( *m_cursor ); + VTool::activate(); +} + +QString +VImageTool::statusText() +{ + return i18n( "Image Tool" ); +} + +void +VImageTool::deactivate() +{ +} + +void +VImageTool::mouseButtonRelease() +{ + QString fname = KFileDialog::getOpenFileName( QString::null, "*.jpg *.gif *.png", view(), i18n( "Choose Image to Add" ) ); + if( !fname.isEmpty() ) + { + VImage *image = new VImage( 0L, fname ); + VInsertImageCmd *cmd = new VInsertImageCmd( &view()->part()->document(), i18n( "Insert Image" ), image, first() ); + + view()->part()->addCommand( cmd, true ); + } +} + +VImageTool::VInsertImageCmd::VInsertImageCmd( VDocument* doc, const QString& name, VImage *image, KoPoint pos ) + : VCommand( doc, name, "frame_image" ), m_image( image ), m_pos( pos ) +{ +} + +void +VImageTool::VInsertImageCmd::execute() +{ + if( !m_image ) + return; + + if( m_image->state() == VObject::deleted ) + m_image->setState( VObject::normal ); + else + { + m_image->setState( VObject::normal ); + m_image->transform( QWMatrix().translate( m_pos.x(), m_pos.y() ) ); + document()->append( m_image ); + document()->selection()->clear(); + document()->selection()->append( m_image ); + } + + setSuccess( true ); +} + +void +VImageTool::VInsertImageCmd::unexecute() +{ + if( !m_image ) + return; + + document()->selection()->take( *m_image ); + m_image->setState( VObject::deleted ); + + setSuccess( false ); +} + +void +VImageTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Image Tool" ), "14_image", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Image" ) ); + m_action->setExclusiveGroup( "misc" ); + //m_ownAction = true; + } +} + diff --git a/karbon/plugins/imagetool/vimagetool.h b/karbon/plugins/imagetool/vimagetool.h new file mode 100644 index 00000000..c9ac7f44 --- /dev/null +++ b/karbon/plugins/imagetool/vimagetool.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __VIMAGETOOL_H__ +#define __VIMAGETOOL_H__ + +#include <qstring.h> + +#include "vtool.h" +#include <commands/vcommand.h> + +class KarbonView; +class VImage; +class QCursor; + +class VImageTool : public VTool +{ +public: + VImageTool( KarbonView *view ); + ~VImageTool(); + + virtual void activate(); + virtual void deactivate(); + + virtual void setup( KActionCollection *collection ); + virtual QString uiname() { return i18n( "Image Tool" ); } + virtual QString contextHelp(); + virtual QString statusText(); + +protected: + class VInsertImageCmd : public VCommand + { + public: + VInsertImageCmd( VDocument* doc, const QString& name, VImage *image, KoPoint pos ); + virtual ~VInsertImageCmd() {} + + virtual void execute(); + virtual void unexecute(); + virtual bool changesSelection() const { return true; } + + protected: + VImage *m_image; + KoPoint m_pos; + }; + + virtual void mouseButtonRelease(); + +private: + QCursor* m_cursor; +}; + +#endif + diff --git a/karbon/plugins/insertknots/Makefile.am b/karbon/plugins/insertknots/Makefile.am new file mode 100644 index 00000000..9f76a527 --- /dev/null +++ b/karbon/plugins/insertknots/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_insertknotsplugin.la + +karbon_insertknotsplugin_la_SOURCES = insertknotsplugin.cc +karbon_insertknotsplugin_la_LIBADD = $(LIB_KPARTS) \ + ../../libkarboncommon.la + +karbon_insertknotsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +partpluginsdir = $(kde_datadir)/karbon/kpartplugins +partplugins_DATA = insertknotsplugin.rc + +METASOURCES = AUTO + diff --git a/karbon/plugins/insertknots/insertknotsplugin.cc b/karbon/plugins/insertknots/insertknotsplugin.cc new file mode 100644 index 00000000..2d470b88 --- /dev/null +++ b/karbon/plugins/insertknots/insertknotsplugin.cc @@ -0,0 +1,118 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "insertknotsplugin.h" +#include <karbon_view.h> +#include <karbon_part.h> +#include <core/vpath.h> +#include <core/vsegment.h> +#include <kgenericfactory.h> +#include <kdebug.h> +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> + +typedef KGenericFactory<InsertKnotsPlugin, KarbonView> InsertKnotsPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_insertknotsplugin, InsertKnotsPluginFactory( "karboninsertknotsplugin" ) ) + +InsertKnotsPlugin::InsertKnotsPlugin( KarbonView *parent, const char* name, const QStringList & ) : Plugin( parent, name ) +{ + new KAction( + i18n( "&Insert Knots..." ), "14_insertknots", 0, this, + SLOT( slotInsertKnots() ), actionCollection(), "path_insert_knots" ); + + m_insertKnotsDlg = new VInsertKnotsDlg(); +} + +void +InsertKnotsPlugin::slotInsertKnots() +{ + KarbonPart *part = ((KarbonView *)parent())->part(); + if( part && m_insertKnotsDlg->exec() ) + part->addCommand( new VInsertKnotsCmd( &part->document(), m_insertKnotsDlg->knots() ), true ); +} + +VInsertKnotsDlg::VInsertKnotsDlg( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Knots" ), Ok | Cancel ) +{ + // add input fields: + QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + new QLabel( i18n( "Knots:" ), group ); + m_knots = new KIntSpinBox( group ); + m_knots->setMinValue( 1 ); + group->setMinimumWidth( 300 ); + + // signals and slots: + connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +uint +VInsertKnotsDlg::knots() const +{ + return m_knots->value(); +} + +void +VInsertKnotsDlg::setKnots( uint value ) +{ + m_knots->setValue( value ); +} + + +VInsertKnotsCmd::VInsertKnotsCmd( VDocument* doc, uint knots ) + : VReplacingCmd( doc, i18n( "Insert Knots" ) ) +{ + m_knots = knots > 0 ? knots : 1; +} + +void +VInsertKnotsCmd::visitVSubpath( VSubpath& path ) +{ + path.first(); + + double length; + + // Ommit first segment. + while( path.next() ) + { + length = path.current()->length(); + + for( uint i = m_knots; i > 0; --i ) + { + path.insert( + path.current()->splitAt( + path.current()->lengthParam( length / ( m_knots + 1.0 ) ) ) ); + + path.next(); + } + + if( !success() ) + setSuccess(); + } +} + +#include "insertknotsplugin.moc" + diff --git a/karbon/plugins/insertknots/insertknotsplugin.h b/karbon/plugins/insertknots/insertknotsplugin.h new file mode 100644 index 00000000..89f0a4d0 --- /dev/null +++ b/karbon/plugins/insertknots/insertknotsplugin.h @@ -0,0 +1,75 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __INSERTKNOTSPLUGIN_H__ +#define __INSERTKNOTSPLUGIN_H__ + +#include <kparts/plugin.h> +#include <kdialogbase.h> +#include <commands/vreplacingcmd.h> + +class VInsertKnotsDlg; +class KarbonView; + +class InsertKnotsPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + InsertKnotsPlugin( KarbonView *parent, const char* name, const QStringList & ); + virtual ~InsertKnotsPlugin() {} + +private slots: + void slotInsertKnots(); + +private: + VInsertKnotsDlg *m_insertKnotsDlg; +}; + +class KIntSpinBox; + +class VInsertKnotsDlg : public KDialogBase +{ + Q_OBJECT + +public: + VInsertKnotsDlg( QWidget* parent = 0L, const char* name = 0L ); + + uint knots() const; + void setKnots( uint value ); + +private: + KIntSpinBox* m_knots; +}; + +class VSubpath; + +class VInsertKnotsCmd : public VReplacingCmd +{ +public: + VInsertKnotsCmd( VDocument* doc, uint knots ); + virtual ~VInsertKnotsCmd() {} + + virtual void visitVSubpath( VSubpath& path ); + +protected: + uint m_knots; +}; + +#endif + diff --git a/karbon/plugins/insertknots/insertknotsplugin.rc b/karbon/plugins/insertknots/insertknotsplugin.rc new file mode 100644 index 00000000..6572440c --- /dev/null +++ b/karbon/plugins/insertknots/insertknotsplugin.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="insertknotsplugin" library="karbon_insertknotsplugin"> +<MenuBar> + <Menu name="effects"> + <Action name="path_insert_knots"/> + </Menu> +</MenuBar> +<ToolBar name="Effects" fullWidth="false"> + <Action name="path_insert_knots"/> +</ToolBar> +</kpartplugin> diff --git a/karbon/plugins/roundcorners/Makefile.am b/karbon/plugins/roundcorners/Makefile.am new file mode 100644 index 00000000..de2ff76c --- /dev/null +++ b/karbon/plugins/roundcorners/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_roundcornersplugin.la + +karbon_roundcornersplugin_la_SOURCES = roundcornersplugin.cc +karbon_roundcornersplugin_la_LIBADD = $(LIB_KPARTS) \ + ../../libkarboncommon.la + +karbon_roundcornersplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +partpluginsdir = $(kde_datadir)/karbon/kpartplugins +partplugins_DATA = roundcornersplugin.rc + +METASOURCES = AUTO + diff --git a/karbon/plugins/roundcorners/roundcornersplugin.cc b/karbon/plugins/roundcorners/roundcornersplugin.cc new file mode 100644 index 00000000..5a36fa51 --- /dev/null +++ b/karbon/plugins/roundcorners/roundcornersplugin.cc @@ -0,0 +1,402 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "roundcornersplugin.h" +#include <karbon_view.h> +#include <karbon_part.h> +#include <core/vpath.h> +#include <core/vsegment.h> +#include <kgenericfactory.h> +#include <kdebug.h> +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> + +typedef KGenericFactory<VRoundCornersPlugin, KarbonView> VRoundCornersPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_roundcornersplugin, VRoundCornersPluginFactory( "karbonroundcornersplugin" ) ) + +VRoundCornersPlugin::VRoundCornersPlugin( KarbonView *parent, const char* name, const QStringList & ) : Plugin( parent, name ) +{ + new KAction( + i18n( "&Round Corners..." ), "14_roundcorners", 0, this, + SLOT( slotRoundCorners() ), actionCollection(), "path_round_corners" ); + + m_roundCornersDlg = new VRoundCornersDlg(); + m_roundCornersDlg->setRadius( 10.0 ); +} + +VRoundCornersPlugin::~VRoundCornersPlugin() +{ +} + +void +VRoundCornersPlugin::slotRoundCorners() +{ + KarbonPart *part = ((KarbonView *)parent())->part(); + if( part && m_roundCornersDlg->exec() ) + part->addCommand( new VRoundCornersCmd( &part->document(), m_roundCornersDlg->radius() ), true ); +} + + +VRoundCornersDlg::VRoundCornersDlg( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Polygonize" ), Ok | Cancel ) +{ + // add input: + QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + new QLabel( i18n( "Round corners:" ), group ); + m_radius = new KDoubleNumInput( group ); + group->setMinimumWidth( 300 ); + + // signals and slots: + connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +double +VRoundCornersDlg::radius() const +{ + return m_radius->value(); +} + +void +VRoundCornersDlg::setRadius( double value ) +{ + m_radius->setValue(value); +} + + + +VRoundCornersCmd::VRoundCornersCmd( VDocument* doc, double radius ) + : VReplacingCmd( doc, i18n( "Round Corners" ) ) +{ + // Set members. + m_radius = radius > 0.0 ? radius : 1.0; +} + +void +VRoundCornersCmd::visitVSubpath( VSubpath& path ) +{ + // Optimize and avoid a crash. + if( path.isEmpty() ) + return; + + // Note: we modiy segments from path. that doesn't hurt, since we + // replace "path" with the temporary path "newPath" afterwards. + + VSubpath newPath( 0L ); + + path.first(); + // Skip "begin". + path.next(); + + /* This algorithm is worked out by <kudling AT kde DOT org> to produce similar results as + * the "round corners" algorithms found in other applications. Neither code nor + * algorithms from any 3rd party is used though. + * + * We want to replace all corners with round corners having "radius" m_radius. + * The algorithm doesn't really produce circular arcs, but that's ok since + * the algorithm achieves nice looking results and is generic enough to be applied + * to all kind of paths. + * Note also, that this algorithm doesn't touch smooth joins (in the sense of + * VSegment::isSmooth() ). + * + * We'll manipulate the input path for bookkeeping purposes and construct a new + * temporary path in parallel. We finally replace the input path with the new path. + * + * + * Without restricting generality, let's assume the input path is closed and + * contains segments which build a rectangle. + * + * 2 + * O------------O + * | | Numbers reflect the segments' order + * 3| |1 in the path. We neglect the "begin" + * | | segment here. + * O------------O + * 0 + * + * There are three unique steps to process. The second step is processed + * many times in a loop. + * + * 1) Begin + * ----- + * Split the first segment of the input path (called "path[0]" here) + * at parameter t + * + * t = path[0]->param( m_radius ) + * + * and move newPath to this new knot. If current segment is too small + * (smaller than 2 * m_radius), we always set t = 0.5 here and in the further + * steps as well. + * + * path: new path: + * + * 2 + * O------------O + * | | + * 3 | | 1 The current segment is marked with "#"s. + * | | + * O##O#########O ...O + * 0 0 + * + * 2) Loop + * ---- + * The loop step is iterated over all segments. After each appliance the index n + * is incremented and the loop step is reapplied until no untouched segment is left. + * + * Split the current segment path[n] of the input path at parameter t + * + * t = path[n]->param( path[n]->length() - m_radius ) + * + * and add the first subsegment of the curent segment to newPath. + * + * path: new path: + * + * 2 + * O------------O + * | | + * 3 | | 1 + * | | + * O--O######O##O O------O... + * 0 0 + * + * Now make the second next segment (the original path[1] segment in our example) + * the current one. Split it at parameter t + * + * t = path[n]->param( m_radius ) + * + * path: new path: + * + * 2 + * O------------O + * | # + * 3 | O 1 + * | # + * O--O------O--O O------O... + * 0 0 + * + * Make the first subsegment of the current segment the current one. + * + * path: new path: + * + * 2 + * O------------O + * | | + * 3 | O 1 O + * | # /.1 + * O--O------O--O O------O... + * 0 0 + * + * 3) End + * --- + * + * path: new path: + * + * 2 4 + * O--O------O--O 5 .O------O. 3 + * | | / \ + * 3 O O 1 6 O O 2 + * | | 7 .\ / + * O--O------O--O ...O------O. 1 + * 0 0 + */ + + double length; + double param; + + // "Begin" step. + // ============= + + // Convert flat beziers to lines. + if( path.current()->isFlat() ) + path.current()->setDegree( 1 ); + + if( path.getLast()->isFlat() ) + path.getLast()->setDegree( 1 ); + + if( + path.isClosed() && + // Don't touch smooth joins. + !path.getLast()->isSmooth( *path.current() ) ) + { + length = path.current()->length(); + + param = length > 2 * m_radius + ? path.current()->lengthParam( m_radius ) + : 0.5; + + + path.insert( + path.current()->splitAt( param ) ); + + newPath.moveTo( + path.current()->knot() ); + + path.next(); + + + if( !success() ) + setSuccess(); + } + else + { + newPath.moveTo( + path.current()->prev()->knot() ); + } + + + // "Loop" step. + // ============ + + while( + path.current() && + path.current()->next() ) + { + // Convert flat beziers to lines. + if( path.current()->isFlat() ) + path.current()->setDegree( 1 ); + + if( path.current()->next()->isFlat() ) + path.current()->next()->setDegree( 1 ); + + + // Don't touch smooth joins. + if( path.current()->isSmooth() ) + { + newPath.append( path.current()->clone() ); + path.next(); + continue; + } + + + // Split the current segment at param( m_radius ) counting + // from the end. + length = path.current()->length(); + + // If the current segment is too short to be split, just don't split it + // because it was split already a t=0.5 during the former step. + if( length > m_radius ) + { + param = path.current()->lengthParam( length - m_radius ); + + path.insert( + path.current()->splitAt( param ) ); + newPath.append( + path.current()->clone() ); + + path.next(); + } + + + // Jump to the next untouched segment. + path.next(); + + + // Split the current segment at param( m_radius ). + length = path.current()->length(); + + param = length > 2 * m_radius + ? path.current()->lengthParam( m_radius ) + : 0.5; + + path.insert( + path.current()->splitAt( param ) ); + + + // Round corner. + newPath.curveTo( + path.current()->prev()->pointAt( 0.5 ), + path.current()->pointAt( 0.5 ), + path.current()->knot() ); + + + if( !success() ) + setSuccess(); + + path.next(); + } + + + // "End" step. + // =========== + + if( path.isClosed() ) + { + // Convert flat beziers to lines. + if( path.current()->isFlat() ) + path.current()->setDegree( 1 ); + + if( path.getFirst()->next()->isFlat() ) + path.getFirst()->next()->setDegree( 1 ); + + // Don't touch smooth joins. + if( !path.current()->isSmooth( *path.getFirst()->next() ) ) + { + length = path.current()->length(); + + // If the current segment is too short to be split, just don't split it + // because it was split already at t=0.5 during the former step. + if( length > m_radius ) + { + param = path.current()->lengthParam( length - m_radius ); + + path.insert( + path.current()->splitAt( param ) ); + newPath.append( + path.current()->clone() ); + + path.next(); + } + + + path.first(); + path.next(); + + // Round corner. + newPath.curveTo( + path.getLast()->pointAt( 0.5 ), + path.current()->pointAt( 0.5 ), + path.current()->knot() ); + + + if( !success() ) + setSuccess(); + } + else + newPath.append( path.current()->clone() ); + + newPath.close(); + } + else + newPath.append( path.current()->clone() ); + + + path = newPath; + + // Invalidate bounding box once. + path.invalidateBoundingBox(); +} + +#include "roundcornersplugin.moc" + diff --git a/karbon/plugins/roundcorners/roundcornersplugin.h b/karbon/plugins/roundcorners/roundcornersplugin.h new file mode 100644 index 00000000..626d698c --- /dev/null +++ b/karbon/plugins/roundcorners/roundcornersplugin.h @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __ROUNDCORNERSPLUGIN_H__ +#define __ROUNDCORNERSPLUGIN_H__ + +#include <kparts/plugin.h> +#include <kdialogbase.h> +#include <commands/vreplacingcmd.h> +#include <koffice_export.h> + +class KarbonView; +class VRoundCornersDlg; + +class KARBONBASE_EXPORT VRoundCornersPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + VRoundCornersPlugin( KarbonView *parent, const char* name, const QStringList & ); + virtual ~VRoundCornersPlugin(); + +private slots: + void slotRoundCorners(); + +private: + VRoundCornersDlg *m_roundCornersDlg; +}; + +class KDoubleNumInput; + +class VRoundCornersDlg : public KDialogBase +{ + Q_OBJECT + +public: + VRoundCornersDlg( QWidget* parent = 0L, const char* name = 0L ); + + double radius() const; + void setRadius( double value ); + +private: + KDoubleNumInput* m_radius; +}; + +class VSubpath; + +class VRoundCornersCmd : public VReplacingCmd +{ +public: + VRoundCornersCmd( VDocument* doc, double radius ); + virtual ~VRoundCornersCmd() {} + + virtual void visitVSubpath( VSubpath& path ); + +protected: + double m_radius; +}; + +#endif + diff --git a/karbon/plugins/roundcorners/roundcornersplugin.rc b/karbon/plugins/roundcorners/roundcornersplugin.rc new file mode 100644 index 00000000..febd47a4 --- /dev/null +++ b/karbon/plugins/roundcorners/roundcornersplugin.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="roundcornersplugin" library="karbon_roundcornersplugin"> +<MenuBar> + <Menu name="effects"> + <Action name="path_round_corners"/> + </Menu> +</MenuBar> +<ToolBar name="Effects" hidden="true" fullWidth="false"> + <Action name="path_round_corners"/> +</ToolBar> +</kpartplugin> diff --git a/karbon/plugins/shadoweffect/Makefile.am b/karbon/plugins/shadoweffect/Makefile.am new file mode 100644 index 00000000..73d9144f --- /dev/null +++ b/karbon/plugins/shadoweffect/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_shadoweffectplugin.la + +karbon_shadoweffectplugin_la_SOURCES = shadoweffectplugin.cc vshadowdecorator.cc +karbon_shadoweffectplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KOFFICEUI) \ + ../../libkarboncommon.la + +karbon_shadoweffectplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +partpluginsdir = $(kde_datadir)/karbon/kpartplugins +partplugins_DATA = shadoweffectplugin.rc + +METASOURCES = AUTO + diff --git a/karbon/plugins/shadoweffect/shadoweffectplugin.cc b/karbon/plugins/shadoweffect/shadoweffectplugin.cc new file mode 100644 index 00000000..c1a0aa33 --- /dev/null +++ b/karbon/plugins/shadoweffect/shadoweffectplugin.cc @@ -0,0 +1,237 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "shadoweffectplugin.h" +#include "klocale.h" +#include <karbon_view.h> +#include <karbon_part.h> +#include <kgenericfactory.h> +#include <kdebug.h> +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> +#include <core/vgroup.h> +#include <core/vpath.h> +#include <core/vsegment.h> +#include <core/vselection.h> +#include <core/vdocument.h> +#include "vshadowdecorator.h" + +typedef KGenericFactory<ShadowEffectPlugin, KarbonView> ShadowEffectPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_shadoweffectplugin, ShadowEffectPluginFactory( "karbonshadoweffectplugin" ) ) + +ShadowEffectPlugin::ShadowEffectPlugin( KarbonView *parent, const char* name, const QStringList & ) +: Plugin( parent, name ) +{ + new KAction( + i18n( "&Shadow Effect..." ), "shadowRB", 0, this, + SLOT( slotShadowEffect() ), actionCollection(), "object_shadow" ); + + m_shadowEffectDlg = new VShadowEffectDlg(); + m_shadowEffectDlg->setDistance( 2 ); + m_shadowEffectDlg->setAngle( 0 ); +} + +void +ShadowEffectPlugin::slotShadowEffect() +{ + KarbonPart *part = ((KarbonView *)parent())->part(); + if( part && m_shadowEffectDlg->exec() ) + part->addCommand( new VCreateShadowCmd( &part->document(), m_shadowEffectDlg->distance(), m_shadowEffectDlg->angle(), double( m_shadowEffectDlg->opacity() ) / 255.0 ), true ); +} + +VShadowEffectDlg::VShadowEffectDlg( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Create Shadow Effect" ), Ok | Cancel ) +{ + // add input fields on the left: + QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + new QLabel( i18n( "Distance:" ), group ); + m_distance = new KIntNumInput( group ); + m_distance->setRange( -1000, 1000, 1, true ); + m_distance->setValue( 2 ); + new QLabel( i18n( "Angle:" ), group ); + m_angle = new KIntNumInput( group ); + m_angle->setRange( 0, 360, 10, true ); + m_angle->setValue( 0 ); + new QLabel( i18n( "Opacity:" ), group ); + m_opacity = new KIntNumInput( group ); + m_opacity->setRange( 0, 100, 1, true ); + m_opacity->setValue( 100 ); + group->setMinimumWidth( 300 ); + m_opacity->setSuffix(i18n("%")); + + // signals and slots: + connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) ); + + setMainWidget( group ); +} + +void +VShadowEffectDlg::setDistance( int d ) +{ + m_distance->setValue( d ); +} + +void +VShadowEffectDlg::setAngle( int a ) +{ + m_angle->setValue( a ); +} + +void +VShadowEffectDlg::setOpacity( int o ) +{ + m_angle->setValue( o ); +} + +int +VShadowEffectDlg::distance() const +{ + return m_distance->value(); +} + +int +VShadowEffectDlg::angle() const +{ + return m_angle->value(); +} + +int +VShadowEffectDlg::opacity() const +{ + return m_opacity->value(); +} + +VCreateShadowCmd::VCreateShadowCmd( VDocument* doc, int distance, int angle, float opacity ) + : VCommand( doc, i18n( "Create Shadow" ) ), m_distance( distance ), m_angle( angle ), m_opacity( opacity ) +{ + // Set members. + m_oldObjects = document()->selection()->clone(); + m_newObjects = 0L; +} + +VCreateShadowCmd::~VCreateShadowCmd() +{ + delete( m_oldObjects ); + delete( m_newObjects ); +} + +void +VCreateShadowCmd::execute() +{ + // Did we have at least once a success? Otherwise we don't get inserted + // into the command history. + bool successful = false; + + + // Create new shapes if they don't exist yet. + if( !m_newObjects ) + { + m_newObjects = new VSelection(); + + // Pointer to temporary object. + VObject* newObject; + + VObjectListIterator itr( m_oldObjects->objects() ); + + for( ; itr.current(); ++itr ) + { + // Clone object and visit the clone. + VShadowDecorator *shadow = dynamic_cast<VShadowDecorator *>( itr.current() ); + if( shadow ) + { + //kdDebug() << "Its a decorator!!!" << endl; + shadow->setShadow( m_distance, m_angle, m_opacity ); + newObject = 0L; + } + else + newObject = new VShadowDecorator( itr.current()->clone(), 0L, m_distance, m_angle, m_opacity ); + + successful = true; + + if(newObject) + { + // Insert new shape right before old shape. + itr.current()->parent()->insertInfrontOf( + newObject, itr.current() ); + + // Add new shape to list of new objects. + m_newObjects->append( newObject ); + } + } + } + + // Nothing to do. + if( m_newObjects->objects().count() == 0 ) + return; + + VObjectListIterator itr( m_oldObjects->objects() ); + + // Hide old objects. + for( ; itr.current(); ++itr ) + { + document()->selection()->take( *itr.current() ); + itr.current()->setState( VObject::deleted ); + } + + // Show new objects. + for( itr = m_newObjects->objects(); itr.current(); ++itr ) + { + itr.current()->setState( VObject::normal ); + document()->selection()->append( itr.current() ); + } + + successful = true; + + // Tell command history wether we had success at least once. + setSuccess( successful ); +} + +void +VCreateShadowCmd::unexecute() +{ + // Nothing to do. + if( m_newObjects->objects().count() == 0 ) + return; + + + VObjectListIterator itr( m_oldObjects->objects() ); + + // Show old objects. + for( ; itr.current(); ++itr ) + { + itr.current()->setState( VObject::normal ); + document()->selection()->append( itr.current() ); + } + + // Hide new objects. + for( itr = m_newObjects->objects(); itr.current(); ++itr ) + { + document()->selection()->take( *itr.current() ); + itr.current()->setState( VObject::deleted ); + } + + // Reset success for command history. + setSuccess( false ); +} + +#include "shadoweffectplugin.moc" + diff --git a/karbon/plugins/shadoweffect/shadoweffectplugin.h b/karbon/plugins/shadoweffect/shadoweffectplugin.h new file mode 100644 index 00000000..9a97da98 --- /dev/null +++ b/karbon/plugins/shadoweffect/shadoweffectplugin.h @@ -0,0 +1,86 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __SHADOWEFFECTPLUGIN_H__ +#define __SHADOWEFFECTPLUGIN_H__ + +#include <kparts/plugin.h> +#include <kdialogbase.h> +#include <commands/vcommand.h> + +class KarbonView; +class VSelection; +class VShadowEffectDlg; + +class ShadowEffectPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + ShadowEffectPlugin( KarbonView *parent, const char* name, const QStringList & ); + virtual ~ShadowEffectPlugin() {} + +private slots: + void slotShadowEffect(); + +private: + VShadowEffectDlg *m_shadowEffectDlg; +}; + +class KIntNumInput; + +class VShadowEffectDlg : public KDialogBase +{ + Q_OBJECT + +public: + VShadowEffectDlg( QWidget* parent = 0L, const char* name = 0L ); + + void setAngle( int ); + void setDistance( int ); + void setOpacity( int ); + + int angle() const; + int distance() const; + int opacity() const; + +private: + KIntNumInput *m_angle; + KIntNumInput *m_distance; + KIntNumInput *m_opacity; +}; + +class VCreateShadowCmd : public VCommand +{ +public: + VCreateShadowCmd( VDocument* doc, int distance, int angle, float opacity ); + virtual ~VCreateShadowCmd(); + + virtual void execute(); + virtual void unexecute(); + virtual bool changesSelection() const { return true; } +private: + VSelection *m_oldObjects; + VSelection *m_newObjects; + int m_distance; + int m_angle; + float m_opacity; +}; + +#endif + diff --git a/karbon/plugins/shadoweffect/shadoweffectplugin.rc b/karbon/plugins/shadoweffect/shadoweffectplugin.rc new file mode 100644 index 00000000..2cfe75af --- /dev/null +++ b/karbon/plugins/shadoweffect/shadoweffectplugin.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="shadoweffectplugin" library="karbon_shadoweffectplugin"> +<MenuBar> + <Menu name="effects"> + <Action name="object_shadow"/> + </Menu> +</MenuBar> +<ToolBar name="Effects" hidden="true" fullWidth="false"> + <Action name="object_shadow"/> +</ToolBar> +</kpartplugin> diff --git a/karbon/plugins/shadoweffect/vshadowdecorator.cc b/karbon/plugins/shadoweffect/vshadowdecorator.cc new file mode 100644 index 00000000..238673ba --- /dev/null +++ b/karbon/plugins/shadoweffect/vshadowdecorator.cc @@ -0,0 +1,150 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vshadowdecorator.h" +#include <core/vfill.h> +#include <core/vstroke.h> +#include <render/vpainter.h> +#include <core/vvisitor.h> +#include <core/vdocument.h> +#include <core/vselection.h> +#include <commands/vtransformcmd.h> + +VShadowDecorator::VShadowDecorator( VObject *object, VObject* parent, int distance, int angle, float opacity ) + : VObject( parent ), m_object( object ), m_distance( distance ), m_angle( angle ), m_opacity( opacity ) +{ +} + +VShadowDecorator::VShadowDecorator( const VShadowDecorator& other ) : VObject( other ) +{ + m_object = other.m_object->clone(); + m_opacity = other.m_opacity; + m_distance = other.m_distance; + m_angle = other.m_angle; +} + +VShadowDecorator::~VShadowDecorator() +{ + delete m_object; +} + +void +VShadowDecorator::draw( VPainter* painter, const KoRect* rect ) const +{ + if( state() == deleted || + state() == hidden || + state() == hidden_locked ) + { + return; + } + + // make sure swallowed object has the same state + m_object->setState( state() ); + + if( state() != VObject::edit ) + { + int shadowDx = int( m_distance * cos( m_angle / 360. * 6.2832 ) ); + int shadowDy = int( m_distance * sin( m_angle / 360. * 6.2832 ) ); + + VFill *fill = new VFill( *m_object->fill() ); + VStroke *stroke = new VStroke( *m_object->stroke() ); + VColor black( Qt::black ); + black.setOpacity( m_opacity ); + if( m_object->fill()->type() != VFill::none ) + m_object->fill()->setColor( black ); + m_object->stroke()->setColor( black ); + QWMatrix mat = painter->worldMatrix(); + painter->setWorldMatrix( mat.translate( shadowDx * painter->zoomFactor(), -shadowDy * painter->zoomFactor()) ); + m_object->draw( painter, rect ); + m_object->setFill( *fill ); + m_object->setStroke( *stroke ); + painter->setWorldMatrix( mat.translate( -shadowDx* painter->zoomFactor() , shadowDy * painter->zoomFactor() ) ); + } + m_object->draw( painter, rect ); +} + +VObject * +VShadowDecorator::clone() const +{ + return new VShadowDecorator( *this ); +} + +void +VShadowDecorator::accept( VVisitor& visitor ) +{ + m_object->accept( visitor ); + visitor.visitVObject( *this ); + // do not allow swallowed object to be part of the selection + document()->selection()->take( *m_object ); +} + +void +VShadowDecorator::setShadow( int distance, int angle, float opacity ) +{ + m_distance = distance; + m_angle = angle; + m_opacity = opacity; +} + +void +VShadowDecorator::setStroke( const VStroke& stroke ) +{ + m_object->setStroke( stroke ); +} + +void +VShadowDecorator::setFill( const VFill& fill ) +{ + m_object->setFill( fill ); +} + +void +VShadowDecorator::setState( const VState state ) +{ + m_state = state; + m_object->setState( state ); +} + +void +VShadowDecorator::save( QDomElement& element ) const +{ + if( m_state != VObject::deleted ) + { + // save shadow as new object + int shadowDx = int( m_distance * cos( m_angle / 360. * 6.2832 ) ); + int shadowDy = int( m_distance * sin( m_angle / 360. * 6.2832 ) ); + + VObject *shadow = m_object->clone(); + + VColor black( Qt::black ); + black.setOpacity( m_opacity ); + if( shadow->fill()->type() != VFill::none ) + shadow->fill()->setColor( black ); + shadow->stroke()->setColor( black ); + QWMatrix mat; + mat.translate( shadowDx, -shadowDy ); + VTransformCmd trafo( 0L, mat ); + trafo.visit( *shadow ); + shadow->save( element ); + delete shadow; + + // save swallowed object + m_object->save( element ); + } +} diff --git a/karbon/plugins/shadoweffect/vshadowdecorator.h b/karbon/plugins/shadoweffect/vshadowdecorator.h new file mode 100644 index 00000000..3ec57e88 --- /dev/null +++ b/karbon/plugins/shadoweffect/vshadowdecorator.h @@ -0,0 +1,64 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSHADOWDECORATOR_H__ +#define __VSHADOWDECORATOR_H__ + + +#include "vobject.h" +#include <koffice_export.h> + +/** + */ +class KARBONBASE_EXPORT VShadowDecorator : public VObject +{ +public: + VShadowDecorator( VObject* object, VObject* parent, int distance = 2, int angle = 0, float opacity = 1.0 ); + VShadowDecorator( const VShadowDecorator& obj ); + + virtual ~VShadowDecorator(); + + virtual void draw( VPainter* /*painter*/, const KoRect* /*rect*/ = 0L ) const; + + virtual const KoRect& boundingBox() const { return m_object->boundingBox(); } + VStroke* stroke() const { return m_object->stroke(); } + virtual void setStroke( const VStroke& stroke ); + VFill* fill() const { return m_object->fill(); } + virtual void setFill( const VFill& fill ); + + virtual void accept( VVisitor& /*visitor*/ ); + + virtual void save( QDomElement& ) const; + virtual void load( const QDomElement& ) {} + + virtual VObject* clone() const; + + VState state() const { return m_state; } + virtual void setState( const VState state ); + + void setShadow( int distance = 2, int angle = 0, float opacity = 1.0 ); +protected: + VObject *m_object; + int m_distance; + int m_angle; + float m_opacity; +}; + +#endif + diff --git a/karbon/plugins/whirlpinch/Makefile.am b/karbon/plugins/whirlpinch/Makefile.am new file mode 100644 index 00000000..a0d53a7c --- /dev/null +++ b/karbon/plugins/whirlpinch/Makefile.am @@ -0,0 +1,16 @@ +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(KOPAINTER_INCLUDES) $(all_includes) + +kde_module_LTLIBRARIES = karbon_whirlpinchplugin.la + +karbon_whirlpinchplugin_la_SOURCES = whirlpinchplugin.cc +karbon_whirlpinchplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KOPAINTER) \ + ../../libkarboncommon.la + + +karbon_whirlpinchplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +partpluginsdir = $(kde_datadir)/karbon/kpartplugins +partplugins_DATA = whirlpinchplugin.rc + +METASOURCES = AUTO + diff --git a/karbon/plugins/whirlpinch/whirlpinchplugin.cc b/karbon/plugins/whirlpinch/whirlpinchplugin.cc new file mode 100644 index 00000000..5c6c716a --- /dev/null +++ b/karbon/plugins/whirlpinch/whirlpinchplugin.cc @@ -0,0 +1,199 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <core/vselection.h> +#include "whirlpinchplugin.h" +#include <karbon_view.h> +#include <karbon_part.h> +#include <kgenericfactory.h> +#include <core/vdocument.h> +#include <core/vcomposite.h> +#include <core/vpath.h> +#include <core/vsegment.h> +#include <core/vglobal.h> + +#include <kdebug.h> + +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> + +typedef KGenericFactory<WhirlPinchPlugin, KarbonView> WhirlPinchPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_whirlpinchplugin, WhirlPinchPluginFactory( "karbonwhirlpinchplugin" ) ) + +WhirlPinchPlugin::WhirlPinchPlugin( KarbonView *parent, const char* name, const QStringList & ) : Plugin( parent, name ) +{ + new KAction( + i18n( "&Whirl/Pinch..." ), "14_whirl", 0, this, + SLOT( slotWhirlPinch() ), actionCollection(), "path_whirlpinch" ); + + m_whirlPinchDlg = new VWhirlPinchDlg(); + m_whirlPinchDlg->setAngle( 20.0 ); + m_whirlPinchDlg->setPinch( 0.0 ); + m_whirlPinchDlg->setRadius( 100.0 ); +} + +void +WhirlPinchPlugin::slotWhirlPinch() +{ + KarbonPart *part = ((KarbonView *)parent())->part(); + if( part && m_whirlPinchDlg->exec() ) + part->addCommand( new VWhirlPinchCmd( &part->document(), m_whirlPinchDlg->angle(), m_whirlPinchDlg->pinch(), m_whirlPinchDlg->radius() ), true ); +} + +VWhirlPinchDlg::VWhirlPinchDlg( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Whirl Pinch" ), Ok | Cancel ) +{ + // add input fields: + QGroupBox* group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + new QLabel( i18n( "Angle:" ), group ); + m_angle = new KDoubleNumInput( group ); + new QLabel( i18n( "Pinch:" ), group ); + m_pinch = new KDoubleNumInput( group ); + new QLabel( i18n( "Radius:" ), group ); + m_radius = new KDoubleNumInput( group ); + group->setMinimumWidth( 300 ); + + // signals and slots: + connect( this, SIGNAL( okClicked() ), this, SLOT( accept() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( reject() ) ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +double +VWhirlPinchDlg::angle() const +{ + return m_angle->value(); +} + +double +VWhirlPinchDlg::pinch() const +{ + return m_pinch->value(); +} + +double +VWhirlPinchDlg::radius() const +{ + return m_radius->value(); +} + +void +VWhirlPinchDlg::setAngle( double value ) +{ + m_angle->setValue( value); +} + +void +VWhirlPinchDlg::setPinch( double value ) +{ + m_pinch->setValue(value); +} + +void +VWhirlPinchDlg::setRadius( double value ) +{ + m_radius->setValue( value); +} + +VWhirlPinchCmd::VWhirlPinchCmd( VDocument* doc, + double angle, double pinch, double radius ) + : VReplacingCmd( doc, i18n( "Whirl Pinch" ) ) +{ + m_angle = angle; + m_pinch = pinch; + m_radius = radius; + m_center = document()->selection()->boundingBox().center(); +} + +VWhirlPinchCmd::~VWhirlPinchCmd() +{ +} + +void +VWhirlPinchCmd::visitVPath( VPath& composite ) +{ + // first subdivide: +// VInsertKnots insertKnots( 2 ); +// insertKnots.visit( composite ); + + VVisitor::visitVPath( composite ); +} + +void +VWhirlPinchCmd::visitVSubpath( VSubpath& path ) +{ + QWMatrix m; + KoPoint delta; + double dist; + + path.first(); + + VSegment *curr = path.current(); + + while( curr ) + { +// TODO: selfmade this function since it's gone: +// path.current()->convertToCurve(); + + // Apply effect to each segment node. + for( int i = 0; i < curr->degree(); ++i ) + { + // calculate distance from whirl center to actual point + delta = curr->point( i ) - m_center; + dist = sqrt( delta.x() * delta.x() + delta.y() * delta.y() ); + + // check if point is inside the whirl radius + if( dist < m_radius ) + { + m.reset(); + + // normalize distance to whirl radius + dist /= m_radius; + + double scale = pow( sin( VGlobal::pi_2 * dist ), -m_pinch ); + // pinch: + m.translate( m_center.x(), m_center.y() ); + m.scale( scale, scale ); + + // whirl: + m.rotate( m_angle * ( 1.0 - dist ) * ( 1.0 - dist ) ); + m.translate( -m_center.x(), -m_center.y() ); + + path.current()->setPoint( i, curr->point( i ).transform( m ) ); + } + + } + + if( !success() ) + setSuccess(); + + curr = path.next(); + } + + // Invalidate bounding box once. + path.invalidateBoundingBox(); +} + +#include "whirlpinchplugin.moc" + diff --git a/karbon/plugins/whirlpinch/whirlpinchplugin.h b/karbon/plugins/whirlpinch/whirlpinchplugin.h new file mode 100644 index 00000000..ffbff5b2 --- /dev/null +++ b/karbon/plugins/whirlpinch/whirlpinchplugin.h @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __WHIRLPINCHPLUGIN_H__ +#define __WHIRLPINCHPLUGIN_H__ + +#include <kdialogbase.h> +#include <kparts/plugin.h> +#include <commands/vreplacingcmd.h> + +class KarbonView; +class VWhirlPinchDlg; + +class WhirlPinchPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + WhirlPinchPlugin( KarbonView *parent, const char* name, const QStringList & ); + virtual ~WhirlPinchPlugin() {} + +private slots: + void slotWhirlPinch(); + +private: + VWhirlPinchDlg *m_whirlPinchDlg; +}; + +class KDoubleNumInput; + +class VWhirlPinchDlg : public KDialogBase +{ + Q_OBJECT + +public: + VWhirlPinchDlg( QWidget* parent = 0L, const char* name = 0L ); + + double angle() const; + double pinch() const; + double radius() const; + void setAngle( double value ); + void setPinch( double value ); + void setRadius( double value ); + +private: + KDoubleNumInput* m_angle; + KDoubleNumInput* m_pinch; + KDoubleNumInput* m_radius; +}; + +class VPath; +class VSubpath; +class VSelection; + +class VWhirlPinchCmd : public VReplacingCmd +{ +public: + VWhirlPinchCmd( VDocument* doc, + double angle, double pinch, double radius ); + virtual ~VWhirlPinchCmd(); + + virtual void visitVPath( VPath& composite ); + virtual void visitVSubpath( VSubpath& path ); + + virtual bool changesSelection() const { return true; } + +protected: + KoPoint m_center; + double m_angle; + double m_pinch; + double m_radius; +}; + +#endif + diff --git a/karbon/plugins/whirlpinch/whirlpinchplugin.rc b/karbon/plugins/whirlpinch/whirlpinchplugin.rc new file mode 100644 index 00000000..797707f7 --- /dev/null +++ b/karbon/plugins/whirlpinch/whirlpinchplugin.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="whirlpinchplugin" library="karbon_whirlpinchplugin"> +<MenuBar> + <Menu name="effects"> + <Action name="path_whirlpinch"/> + </Menu> +</MenuBar> +<ToolBar name="Effects" hidden="true" fullWidth="false"> + <Action name="path_whirlpinch"/> +</ToolBar> +</kpartplugin> diff --git a/karbon/plugins/zoomtool/Makefile.am b/karbon/plugins/zoomtool/Makefile.am new file mode 100644 index 00000000..a0883c96 --- /dev/null +++ b/karbon/plugins/zoomtool/Makefile.am @@ -0,0 +1,14 @@ +kde_services_DATA = karbonzoomtool.desktop + +INCLUDES = $(KOFFICE_INCLUDES) -I$(top_srcdir)/karbon -I$(top_srcdir)/karbon/core $(all_includes) + +kde_module_LTLIBRARIES = karbon_zoomtoolplugin.la + +karbon_zoomtoolplugin_la_SOURCES = vzoomtool.cc zoomtoolplugin.cc +karbon_zoomtoolplugin_la_LIBADD = $(LIB_KPARTS) $(LIB_KOFFICEUI) \ + ../../libkarboncommon.la + +karbon_zoomtoolplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +METASOURCES = AUTO + diff --git a/karbon/plugins/zoomtool/karbonzoomtool.desktop b/karbon/plugins/zoomtool/karbonzoomtool.desktop new file mode 100644 index 00000000..3692ac54 --- /dev/null +++ b/karbon/plugins/zoomtool/karbonzoomtool.desktop @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Zoom Tool +Name[bg]=Инструмент за мащаб +Name[br]=Ostilh Zoom +Name[ca]=Eina per a apropar/allunyar +Name[cy]=Erfyn Chwyddo +Name[da]=Forstørrelsesværktøj +Name[de]=Zoom-Werkzeug +Name[el]=Εργαλείο εστίασης +Name[eo]=Zomilo +Name[es]=Herramienta para zoom +Name[et]=Suurendustööriist +Name[fa]=ابزار بزرگنمایی +Name[fi]=Zoomaustyökalu +Name[fr]=Outil de zoom +Name[fy]=Zoomark +Name[ga]=Uirlis Súmála +Name[gl]=Ferramenta de Ampliación +Name[hr]=Alat za uvećavanje +Name[hu]=Nagyító +Name[is]=Stækkunartól +Name[it]=Strumento di ingrandimento +Name[ja]=ズームツール +Name[km]=ឧបករណ៍ពង្រីក +Name[lt]=Didinimo įrankis +Name[lv]=Tālummaiņas rīks +Name[nb]=Verktøy som forstørrer/forminsker +Name[nds]=Vergröttern-Warktüüch +Name[ne]=जूम उपकरण +Name[nl]=Zoomgereedschap +Name[pl]=Narzędzie powiększenia +Name[pt]=Ferramenta de Ampliação +Name[pt_BR]=Ferramenta de Ampliação +Name[ru]=Масштабирование +Name[se]=Stuoridan-/unnidanreaidu +Name[sk]=Nástroj lupa +Name[sl]=Orodje za povečavo +Name[sr]=Алат за увећање +Name[sr@Latn]=Alat za uvećanje +Name[sv]=Zoomverktyg +Name[uk]=Засіб масштабування +Name[uz]=Kattalashtirish vositasi +Name[uz@cyrillic]=Катталаштириш воситаси +Name[zh_CN]=缩放工具 +Name[zh_TW]=縮放工具 +ServiceTypes=Karbon/CoreModule +Type=Service +X-KDE-Library=karbon_zoomtoolplugin diff --git a/karbon/plugins/zoomtool/vzoomtool.cc b/karbon/plugins/zoomtool/vzoomtool.cc new file mode 100644 index 00000000..60142481 --- /dev/null +++ b/karbon/plugins/zoomtool/vzoomtool.cc @@ -0,0 +1,170 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <qcursor.h> +#include <qevent.h> + +#include <klocale.h> + +#include "vzoomtool.h" +#include <karbon_part.h> +#include <karbon_part.h> +#include <karbon_view.h> +#include <karbon_view.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <core/vcursor.h> + +VZoomTool::VZoomTool(KarbonView *view ): VTool( view, "tool_zoom_plugin" ) +{ + m_plusCursor = new QCursor( VCursor::createCursor( VCursor::ZoomPlus ) ); + + registerTool( this ); +} + +VZoomTool::~VZoomTool() +{ + delete m_plusCursor; +} + +QString +VZoomTool::contextHelp() +{ + QString s = i18n( "<qt><b>Zoom tool:</b><br>" ); + s += i18n( "<i>Click and drag</i> to zoom into a rectangular area.<br>" ); + s += i18n( "<i>Right click</i> to zoom out of canvas.<br>" ); + s += i18n( "<i>Pressing +/- keys</i><br>to zoom into/out of canvas." ); + return s; +} + +void +VZoomTool::activate() +{ + VTool::activate(); + view()->setCursor( *m_plusCursor ); +} + +QString +VZoomTool::statusText() +{ + return i18n( "Zoom Tool" ); +} + +void +VZoomTool::deactivate() +{ +} + +void +VZoomTool::draw() +{ + VPainter *painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + if( isDragging() ) + { + painter->setPen( Qt::DotLine ); + painter->newPath(); + painter->moveTo( KoPoint( first().x(), first().y() ) ); + painter->lineTo( KoPoint( m_current.x(), first().y() ) ); + painter->lineTo( KoPoint( m_current.x(), m_current.y() ) ); + painter->lineTo( KoPoint( first().x(), m_current.y() ) ); + painter->lineTo( KoPoint( first().x(), first().y() ) ); + painter->strokePath(); + } +} + +void +VZoomTool::mouseButtonPress() +{ + m_current = first(); + + recalc(); + + draw(); +} + +void +VZoomTool::rightMouseButtonRelease() +{ + view()->setZoomAt( view()->zoom() * 0.75, last() ); +} + +void +VZoomTool::mouseButtonRelease() +{ + view()->setZoomAt( view()->zoom() * 1.5, last() ); +} + +void +VZoomTool::mouseDrag() +{ + draw(); + + recalc(); + + draw(); +} + +void +VZoomTool::mouseDragRelease() +{ + KoRect rect( first().x(), first().y(), last().x() - first().x(), last().y() - first().y() ); + rect = rect.normalize(); + view()->setViewportRect( rect ); +} + +bool +VZoomTool::keyReleased( Qt::Key key ) +{ + double zoomChange = 0; + if( key == Qt::Key_Minus ) + zoomChange = 0.75; + else if( key == Qt::Key_Plus ) + zoomChange = 1.50; + + if( zoomChange != 0 ) + { + view()->setZoomAt( view()->zoom() * zoomChange ); + return true; + } + return false; +} + +void +VZoomTool::recalc() +{ + m_current = last(); +} + +void +VZoomTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Zoom Tool" ), "14_zoom", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Zoom" ) ); + m_action->setExclusiveGroup( "misc" ); + //m_ownAction = true; + } +} + diff --git a/karbon/plugins/zoomtool/vzoomtool.h b/karbon/plugins/zoomtool/vzoomtool.h new file mode 100644 index 00000000..2616c03f --- /dev/null +++ b/karbon/plugins/zoomtool/vzoomtool.h @@ -0,0 +1,69 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __VZOOMTOOL_H__ +#define __VZOOMTOOL_H__ + +#include "KoPoint.h" +#include <qstring.h> + +#include "vtool.h" + +class QCursor; + +class KarbonView; + +class VZoomTool : public VTool +{ +public: + VZoomTool( KarbonView *view ); + ~VZoomTool(); + + virtual void activate(); + virtual void deactivate(); + + virtual void setup( KActionCollection *collection ); + virtual QString uiname() { return i18n( "Zoom Tool" ); } + virtual QString contextHelp(); + virtual QString statusText(); + +protected: + void draw(); + + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + + virtual bool keyReleased( Qt::Key key ); + + virtual void rightMouseButtonRelease(); + + void recalc(); + + KoPoint m_current; + +private: + QCursor* m_plusCursor; + +}; + +#endif + diff --git a/karbon/plugins/zoomtool/zoomtoolplugin.cc b/karbon/plugins/zoomtool/zoomtoolplugin.cc new file mode 100644 index 00000000..fefec1d9 --- /dev/null +++ b/karbon/plugins/zoomtool/zoomtoolplugin.cc @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <kgenericfactory.h> + +#include "karbon_factory.h" +#include "karbon_tool_factory.h" +#include "karbon_tool_registry.h" + +#include "zoomtoolplugin.h" +#include "vzoomtool.h" + +typedef KGenericFactory<ZoomToolPlugin> ZoomToolPluginFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_zoomtoolplugin, ZoomToolPluginFactory( "karbonzoomtoolplugin" ) ) + +ZoomToolPlugin::ZoomToolPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ZoomToolPluginFactory::instance()); + + kdDebug() << "Zoom tool plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if ( parent->inherits("KarbonFactory") ) + { + KarbonToolRegistry* r = KarbonToolRegistry::instance(); + r -> add(new KarbonToolFactory<VZoomTool>()); + } + +} + +ZoomToolPlugin::~ZoomToolPlugin() +{ +} + +#include "zoomtoolplugin.moc" diff --git a/karbon/plugins/zoomtool/zoomtoolplugin.h b/karbon/plugins/zoomtool/zoomtoolplugin.h new file mode 100644 index 00000000..488526c7 --- /dev/null +++ b/karbon/plugins/zoomtool/zoomtoolplugin.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __ZOOMTOOLPLUGIN_H__ +#define __ZOOMTOOLPLUGIN_H__ + +#include <qstring.h> + +#include <kparts/plugin.h> + +/** + * A module that provides a zoom tool. + */ +class ZoomToolPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + ZoomToolPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~ZoomToolPlugin(); +}; + +#endif // __ZOOMTOOLPLUGIN_H__ + + diff --git a/karbon/plugins/zoomtool/zoomtoolplugin.rc b/karbon/plugins/zoomtool/zoomtoolplugin.rc new file mode 100644 index 00000000..14a6399c --- /dev/null +++ b/karbon/plugins/zoomtool/zoomtoolplugin.rc @@ -0,0 +1,3 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="zoomtoolplugin" library="karbon_zoomtoolplugin"> +</kpartplugin> diff --git a/karbon/render/Makefile.am b/karbon/render/Makefile.am new file mode 100644 index 00000000..5f604f6c --- /dev/null +++ b/karbon/render/Makefile.am @@ -0,0 +1,34 @@ +SUBDIRS = xrgbrender + +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/xrgbrender \ + -I$(srcdir)/../core \ + $(LIBART_CFLAGS) \ + $(all_includes) + +noinst_LTLIBRARIES = libvpainter.la + +noinst_HEADERS = \ + vpainter.h \ + vpainterfactory.h \ + vqpainter.h \ + art_render_pattern.h \ + art_render_misc.h \ + art_rgb_svp.h \ + art_rgb.h \ + art_rgba_affine.h \ + vkopainter.h + +libvpainter_la_SOURCES = \ + vpainterfactory.cc \ + vqpainter.cc \ + art_render_pattern.c \ + art_render_misc.c \ + art_rgb_svp.c \ + art_rgb.c \ + art_rgba_affine.c \ + vkopainter.cc + +libvpainter_la_METASOURCES = \ + AUTO diff --git a/karbon/render/art_render_misc.c b/karbon/render/art_render_misc.c new file mode 100644 index 00000000..088a3984 --- /dev/null +++ b/karbon/render/art_render_misc.c @@ -0,0 +1,403 @@ +/* This file is part of the KDE project. + * art_render_misc.c: Here I store some routines I feel should be in libart :) + * + * Copyright (C) 2002, The Karbon Developers + * + * This code is adapted from : + * + * art_render_gradient.c: Gradient image source for modular rendering. + * + * Libart_LGPL - library of basic graphic primitives + * Copyright (C) 2000 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Authors: Raph Levien <raph@acm.org> + * Alexander Larsson <alla@lysator.liu.se> + */ + +#include "config.h" +#include "art_render_misc.h" + +#include <math.h> + +typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin; +typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad; +typedef struct _ArtImageSourceGradCon ArtImageSourceGradCon; + +struct _ArtImageSourceGradLin { + ArtImageSource super; + const ArtGradientLinear *gradient; +}; + +struct _ArtImageSourceGradRad { + ArtImageSource super; + const ArtGradientRadial *gradient; + double a; +}; + +struct _ArtImageSourceGradCon { + ArtImageSource super; + const ArtGradientConical *gradient; +}; + + +#define EPSILON 1e-6 + +/** + * art_karbon_render_gradient_setpix: Set a gradient pixel. + * @render: The render object. + * @dst: Pointer to destination (where to store pixel). + * @n_stops: Number of stops in @stops. + * @stops: The stops for the gradient. + * @offset: The offset. + * + * @n_stops must be > 0. + * + * Sets a gradient pixel, storing it at @dst. + **/ +static void +art_karbon_render_gradient_setpix (ArtRender *render, + art_u8 *dst, + int n_stops, ArtGradientStop *stops, + double offset) +{ + int ix; + int j; + double off0, off1; + int n_ch = render->n_chan + 1; + + for (ix = 0; ix < n_stops; ix++) + if (stops[ix].offset > offset) + break; + /* stops[ix - 1].offset < offset < stops[ix].offset */ + if (ix > 0 && ix < n_stops) + { + off0 = stops[ix - 1].offset; + off1 = stops[ix].offset; + if (fabs (off1 - off0) > EPSILON) + { + double interp; + + interp = (offset - off0) / (off1 - off0); + for (j = 0; j < n_ch; j++) + { + int z0, z1; + int z; + z0 = stops[ix - 1].color[j]; + z1 = stops[ix].color[j]; + z = floor (z0 + (z1 - z0) * interp + 0.5); + if (render->buf_depth == 8) + dst[j] = ART_PIX_8_FROM_MAX (z); + else /* (render->buf_depth == 16) */ + ((art_u16 *)dst)[j] = z; + } + return; + } + } + else if (ix == n_stops) + ix--; + + for (j = 0; j < n_ch; j++) + { + int z; + z = stops[ix].color[j]; + if (render->buf_depth == 8) + dst[j] = ART_PIX_8_FROM_MAX (z); + else /* (render->buf_depth == 16) */ + ((art_u16 *)dst)[j] = z; + } +} + +static void +art_karbon_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_karbon_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self; + const ArtGradientLinear *gradient = z->gradient; + int pixstride = (render->n_chan + 1) * (render->depth >> 3); + int x; + int width = render->x1 - render->x0; + double offset, d_offset; + double actual_offset; + int n_stops = gradient->n_stops; + ArtGradientStop *stops = gradient->stops; + art_u8 *bufp = render->image_buf; + ArtGradientSpread spread = gradient->spread; + + offset = render->x0 * gradient->a + y * gradient->b + gradient->c; + d_offset = gradient->a; + + for (x = 0; x < width; x++) + { + if (spread == ART_GRADIENT_PAD) + actual_offset = offset; + else if (spread == ART_GRADIENT_REPEAT) + actual_offset = offset - floor (offset); + else /* (spread == ART_GRADIENT_REFLECT) */ + { + double tmp; + + tmp = offset - 2 * floor (0.5 * offset); + actual_offset = tmp > 1 ? 2 - tmp : tmp; + } + art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset); + offset += d_offset; + bufp += pixstride; + } +} + +static void +art_karbon_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + self->super.render = art_karbon_render_gradient_linear_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_PREMUL; +} + +/** + * art_karbon_render_gradient_linear: Add a linear gradient image source. + * @render: The render object. + * @gradient: The linear gradient. + * + * Adds the linear gradient @gradient as the image source for rendering + * in the render object @render. + **/ +void +art_karbon_render_gradient_linear (ArtRender *render, + const ArtGradientLinear *gradient, + ArtFilterLevel level) +{ + ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1); + + image_source->super.super.render = NULL; + image_source->super.super.done = art_karbon_render_gradient_linear_done; + image_source->super.negotiate = art_karbon_render_gradient_linear_negotiate; + + image_source->gradient = gradient; + + art_render_add_image_source (render, &image_source->super); +} + +static void +art_karbon_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_karbon_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self; + const ArtGradientRadial *gradient = z->gradient; + int pixstride = (render->n_chan + 1) * (render->depth >> 3); + int x; + int x0 = render->x0; + int width = render->x1 - x0; + int n_stops = gradient->n_stops; + ArtGradientStop *stops = gradient->stops; + art_u8 *bufp = render->image_buf; + double fx = gradient->fx; + double fy = gradient->fy; + double dx, dy; + double *affine = gradient->affine; + double aff0 = affine[0]; + double aff1 = affine[1]; + const double a = z->a; + const double arecip = 1.0 / a; + double b, db; + double c, dc, ddc; + double b_a, db_a; + double rad, drad, ddrad; + ArtGradientSpread spread = gradient->spread; + + dx = x0 * aff0 + y * affine[2] + affine[4] - fx; + dy = x0 * aff1 + y * affine[3] + affine[5] - fy; + b = dx * fx + dy * fy; + db = aff0 * fx + aff1 * fy; + c = dx * dx + dy * dy; + dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1; + ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1; + + b_a = b * arecip; + db_a = db * arecip; + + rad = b_a * b_a + c * arecip; + drad = 2 * b_a * db_a + db_a * db_a + dc * arecip; + ddrad = 2 * db_a * db_a + ddc * arecip; + + for (x = 0; x < width; x++) + { + double z; + + if (rad > 0) + z = b_a + sqrt (rad); + else + z = b_a; + + if (spread == ART_GRADIENT_REPEAT) + z = z - floor (z); + else if (spread == ART_GRADIENT_REFLECT) + { + double tmp; + + tmp = z - 2 * floor (0.5 * z); + z = tmp > 1 ? 2 - tmp : tmp; + } + + art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z); + bufp += pixstride; + b_a += db_a; + rad += drad; + drad += ddrad; + } +} + +static void +art_karbon_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + self->super.render = art_karbon_render_gradient_radial_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_PREMUL; +} + +/** + * art_karbon_render_gradient_radial: Add a radial gradient image source. + * @render: The render object. + * @gradient: The radial gradient. + * + * Adds the radial gradient @gradient as the image source for rendering + * in the render object @render. + **/ +void +art_karbon_render_gradient_radial (ArtRender *render, + const ArtGradientRadial *gradient, + ArtFilterLevel level) +{ + ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1); + double fx = gradient->fx; + double fy = gradient->fy; + + image_source->super.super.render = NULL; + image_source->super.super.done = art_karbon_render_gradient_radial_done; + image_source->super.negotiate = art_karbon_render_gradient_radial_negotiate; + + image_source->gradient = gradient; + /* todo: sanitycheck fx, fy? */ + image_source->a = 1 - fx * fx - fy * fy; + + art_render_add_image_source (render, &image_source->super); +} + +/* Conical */ + +static void +art_render_gradient_conical_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_render_gradient_conical_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourceGradCon *z = (ArtImageSourceGradCon *)self; + const ArtGradientConical *gradient = z->gradient; + int pixstride = (render->n_chan + 1) * (render->depth >> 3); + int x; + int x0 = render->x0; + int width = render->x1 - x0; + int n_stops = gradient->n_stops; + ArtGradientStop *stops = gradient->stops; + art_u8 *bufp = render->image_buf; + double cx = gradient->cx; + double cy = gradient->cy; + double r = gradient->r; + double dx, dy; + ArtGradientSpread spread = gradient->spread; + + dy = fabs(y) - fabs(cy); + + for (x = 0; x < width; x++) + { + double z; + dx = fabs(x0 + x) - fabs(cx); + + z = (fabs(dx) + fabs(dy)) / (r); + + if (spread == ART_GRADIENT_REPEAT) + z = z - floor (z); + else if (spread == ART_GRADIENT_REFLECT) + { + double tmp; + + tmp = z - 2 * floor (0.5 * z); + z = tmp > 1 ? 2 - tmp : tmp; + } + + art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z); + bufp += pixstride; + } +} + +static void +art_render_gradient_conical_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + self->super.render = art_render_gradient_conical_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_PREMUL; +} + +/** + * art_render_gradient_radial: Add a radial gradient image source. + * @render: The render object. + * @gradient: The radial gradient. + * + * Adds the radial gradient @gradient as the image source for rendering + * in the render object @render. + **/ +void +art_karbon_render_gradient_conical (ArtRender *render, + const ArtGradientConical *gradient, + ArtFilterLevel level) +{ + ArtImageSourceGradCon *image_source = art_new (ArtImageSourceGradCon, 1); + + image_source->super.super.render = NULL; + image_source->super.super.done = art_render_gradient_conical_done; + image_source->super.negotiate = art_render_gradient_conical_negotiate; + + image_source->gradient = gradient; + + art_render_add_image_source (render, &image_source->super); +} + diff --git a/karbon/render/art_render_misc.h b/karbon/render/art_render_misc.h new file mode 100644 index 00000000..9d4b444c --- /dev/null +++ b/karbon/render/art_render_misc.h @@ -0,0 +1,109 @@ +/* This file is part of the KDE project. + * art_render_misc.c: Here I store some routines I feel should be in libart :) + * + * Copyright (C) 2002, The Karbon Developers + * + * This code is adapted from : + * + * art_render_gradient.h: Gradient image source for modular rendering. + * + * Libart_LGPL - library of basic graphic primitives + * Copyright (C) 2000 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Authors: Raph Levien <raph@acm.org> + * Alexander Larsson <alla@lysator.liu.se> + */ + +#ifndef __ART_RENDER_MISC_H__ +#define __ART_RENDER_MISC_H__ + +#ifdef LIBART_COMPILATION +#include "art_filterlevel.h" +#include "art_render.h" +#else +#include <libart_lgpl/art_filterlevel.h> +#include <libart_lgpl/art_render.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _ArtGradientLinear ArtGradientLinear; +typedef struct _ArtGradientRadial ArtGradientRadial; +typedef struct _ArtGradientConical ArtGradientConical; +typedef struct _ArtGradientStop ArtGradientStop; + +typedef enum { + ART_GRADIENT_PAD, + ART_GRADIENT_REFLECT, + ART_GRADIENT_REPEAT +} ArtGradientSpread; + +struct _ArtGradientLinear { + double a; + double b; + double c; + ArtGradientSpread spread; + int n_stops; + ArtGradientStop *stops; +}; + +struct _ArtGradientRadial { + double affine[6]; /* transforms user coordinates to unit circle */ + double fx, fy; /* focal point in unit circle coords */ + int n_stops; + ArtGradientSpread spread; + ArtGradientStop *stops; +}; + +struct _ArtGradientConical { + double cx, cy; /* focal point in unit circle coords */ + double r; /* focal point in unit circle coords */ + ArtGradientSpread spread; + art_u8 *buf; + int n_stops; + ArtGradientStop *stops; +}; + + +struct _ArtGradientStop { + double offset; + ArtPixMaxDepth color[ART_MAX_CHAN + 1]; +}; + +void +art_karbon_render_gradient_linear (ArtRender *render, + const ArtGradientLinear *gradient, + ArtFilterLevel level); + +void +art_karbon_render_gradient_radial (ArtRender *render, + const ArtGradientRadial *gradient, + ArtFilterLevel level); + +void +art_karbon_render_gradient_conical (ArtRender *render, + const ArtGradientConical *gradient, + ArtFilterLevel level); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ART_RENDER_MISC_H__ */ diff --git a/karbon/render/art_render_pattern.c b/karbon/render/art_render_pattern.c new file mode 100644 index 00000000..9245402d --- /dev/null +++ b/karbon/render/art_render_pattern.c @@ -0,0 +1,111 @@ +/* + * art_render_pattern.c: + * + * Libart_LGPL - library of basic graphic primitives + * Copyright (C) 2000 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "art_render_pattern.h" + +#include <math.h> + +typedef struct _ArtImageSourcePattern ArtImageSourcePattern; + +struct _ArtImageSourcePattern { + ArtImageSource super; + const ArtPattern *pattern; +}; + +static void +art_render_pattern_done (ArtRenderCallback *self, ArtRender *render) +{ + art_free (self); +} + +static void +art_render_pattern_render (ArtRenderCallback *self, ArtRender *render, + art_u8 *dest, int y) +{ + ArtImageSourcePattern *z = (ArtImageSourcePattern *)self; + const ArtPattern *pattern = z->pattern; + int pixstride = (render->n_chan + 1) * (render->depth >> 3); + int n_ch = render->n_chan + 1; + int x, j, index; + int width = render->x1 - render->x0; + int twidth = pattern->twidth; + int theight = pattern->theight; + art_u8 *bufp = render->image_buf; + + double angle = pattern->angle; + double opacity = pattern->opacity; + double cosangle = cos(angle); + double sinangle = sin(angle); + + y = y - render->y0; + + if(theight == 0) return; + + for (x = 0; x < width; x++) + { + int x0 = sinangle * y + cosangle * x; + int y0 = -sinangle * x + cosangle * y; + x0 = (x0 % twidth); + if(x0 < 0) x0 += twidth; + y0 = (y0 % theight); + if(y0 < 0) y0 += theight; + index = (((y0 * twidth + x0) * pixstride) % (twidth * theight * 4)); + /*for (j = 0; j < n_ch - 1; j++) + {*/ + /* bgra -> rgba */ + bufp[0] = pattern->buffer[index + 2]; + bufp[1] = pattern->buffer[index + 1]; + bufp[2] = pattern->buffer[index + 0]; + bufp[3] = opacity; + /*}*/ + bufp += pixstride; + } +} + +static void +art_render_pattern_negotiate (ArtImageSource *self, ArtRender *render, + ArtImageSourceFlags *p_flags, + int *p_buf_depth, ArtAlphaType *p_alpha) +{ + self->super.render = art_render_pattern_render; + *p_flags = 0; + *p_buf_depth = render->depth; + *p_alpha = ART_ALPHA_SEPARATE; +} + +void +art_render_pattern (ArtRender *render, + const ArtPattern *pattern, + ArtFilterLevel level) +{ + ArtImageSourcePattern *image_source = art_new (ArtImageSourcePattern, 1); + + image_source->super.super.render = NULL; + image_source->super.super.done = art_render_pattern_done; + image_source->super.negotiate = art_render_pattern_negotiate; + + image_source->pattern = pattern; + + art_render_add_image_source (render, &image_source->super); +} diff --git a/karbon/render/art_render_pattern.h b/karbon/render/art_render_pattern.h new file mode 100644 index 00000000..c70b76c6 --- /dev/null +++ b/karbon/render/art_render_pattern.h @@ -0,0 +1,58 @@ +/* + * art_render_pattern.h: + * + * Libart_LGPL - library of basic graphic primitives + * Copyright (C) 2000 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __ART_RENDER_PATTERN_H__ +#define __ART_RENDER_PATTERN_H__ + +#ifdef LIBART_COMPILATION +#include "art_filterlevel.h" +#include "art_render.h" +#else +#include <libart_lgpl/art_filterlevel.h> +#include <libart_lgpl/art_render.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _ArtPattern ArtPattern; + +struct _ArtPattern { + unsigned int twidth; /* width of tile */ + unsigned int theight; /* height of tile */ + art_u8 opacity; /* opacity level */ + double angle; + art_u8 *buffer; /* image source */ +}; + +void +art_render_pattern (ArtRender *render, + const ArtPattern *pattern, + ArtFilterLevel level); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ART_RENDER_PATTERN_H__ */ diff --git a/karbon/render/art_rgb.c b/karbon/render/art_rgb.c new file mode 100644 index 00000000..4d30fad4 --- /dev/null +++ b/karbon/render/art_rgb.c @@ -0,0 +1,174 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "art_rgb.h" + +#include <string.h> /* for memset */ + +/* Basic operators for manipulating 24-bit packed RGB buffers. */ + +#define COLOR_RUN_SIMPLE + +#ifdef COLOR_RUN_SIMPLE +/* This is really slow. Is there any way we might speed it up? + Two ideas: + + First, maybe we should be working at 32-bit alignment. Then, + this can be a simple loop over word stores. + + Second, we can keep working at 24-bit alignment, but have some + intelligence about storing. For example, we can iterate over + 4-pixel chunks (aligned at 4 pixels), with an inner loop + something like: + + *buf++ = v1; + *buf++ = v2; + *buf++ = v3; + + One source of extra complexity is the need to make sure linebuf is + aligned to a 32-bit boundary. + + This second alternative has some complexity to it, but is + appealing because it really minimizes the memory bandwidth. */ +void +art_rgb_fill_run_ (art_u8 *buf, art_u32 rgb, int n) +{ + int i; + art_u32 *b = (art_u32 *)buf; + for (i = 0; i < n; i++) + { + *b = rgb; + b++; + } +} +#endif + +#ifdef COLOR_RUN_COMPLEX +/* This implements the second of the two ideas above. The test results + are _very_ encouraging - it seems the speed is within 10% of + memset, which is quite good! */ +/** + * art_rgb_fill_run: fill a buffer a solid RGB color. + * @buf: Buffer to fill. + * @r: Red, range 0..255. + * @g: Green, range 0..255. + * @b: Blue, range 0..255. + * @n: Number of RGB triples to fill. + * + * Fills a buffer with @n copies of the (@r, @g, @b) triple. Thus, + * locations @buf (inclusive) through @buf + 3 * @n (exclusive) are + * written. + * + * The implementation of this routine is very highly optimized. + **/ +void +art_rgb_fill_run_ (art_u8 *buf, art_u32 rgb, int n) +{ + int i; + unsigned int v1, v2, v3; + + if (r == g && g == b) + { + memset (buf, g, 4*n); + } + else + { + if (n < 8) + { + for (i = 0; i < n; i++) + { + buf++; + *buf++ = r; + *buf++ = g; + *buf++ = b; + } + } else { + /* handle prefix up to byte alignment */ + /* I'm worried about this cast on sizeof(long) != sizeof(uchar *) + architectures, but it _should_ work. */ + for (i = 0; ((unsigned long)buf) & 3; i++) + { + buf++; + *buf++ = r; + *buf++ = g; + *buf++ = b; + } +#ifndef WORDS_BIGENDIAN + v1 = r | (g << 8) | (b << 16) | (r << 24); + v3 = (v1 << 8) | b; + v2 = (v3 << 8) | g; +#else + v1 = (r << 24) | (g << 16) | (b << 8) | r; + v2 = (v1 << 8) | g; + v3 = (v2 << 8) | b; +#endif + for (; i < n - 3; i += 4) + {/* + ((art_u32 *)buf)[0] = v1; + ((art_u32 *)buf)[1] = v2; + ((art_u32 *)buf)[2] = v3; + buf += 12;*/ + ((art_u32 *)buf)[1] = v1; + ((art_u32 *)buf)[2] = v2; + ((art_u32 *)buf)[3] = v3; + buf += 16; + } + /* handle postfix */ + for (; i < n; i++) + { + buf++; + *buf++ = r; + *buf++ = g; + *buf++ = b; + } + } + } +} +#endif + +/** + * art_rgb_run_alpha: Render semitransparent color over RGB buffer. + * @buf: Buffer for rendering. + * @r: Red, range 0..255. + * @g: Green, range 0..255. + * @b: Blue, range 0..255. + * @alpha: Alpha, range 0..256. + * @n: Number of RGB triples to render. + * + * Renders a sequential run of solid (@r, @g, @b) color over @buf with + * opacity @alpha. + **/ +void +art_rgb_run_alpha_ (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n) +{ + int i; + int v; + for (i = 0; i < n; i++) + { + v = *buf; + *buf++ = v + (((b - v) * alpha + 0x80) >> 8); + v = *buf; + *buf++ = v + (((g - v) * alpha + 0x80) >> 8); + v = *buf; + *buf++ = v + (((r - v) * alpha + 0x80) >> 8); + buf++; + } +} + diff --git a/karbon/render/art_rgb.h b/karbon/render/art_rgb.h new file mode 100644 index 00000000..1f2c6919 --- /dev/null +++ b/karbon/render/art_rgb.h @@ -0,0 +1,44 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ART_RGB_H__ +#define __ART_RGB_H__ + +#ifdef LIBART_COMPILATION +#include "art_misc.h" +#else +#include <libart_lgpl/art_misc.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void +art_rgb_fill_run_ (art_u8 *buf, art_u32 rgb, int n); + +void +art_rgb_run_alpha_ (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, + int n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/karbon/render/art_rgb_affine_private.c b/karbon/render/art_rgb_affine_private.c new file mode 100644 index 00000000..4a92a301 --- /dev/null +++ b/karbon/render/art_rgb_affine_private.c @@ -0,0 +1,127 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "art_rgb_affine_private.h" + +#include <math.h> +#include <libart_lgpl/art_misc.h> +#include <libart_lgpl/art_point.h> +#include <libart_lgpl/art_affine.h> + +/* Private functions for the rgb affine image compositors - primarily, + the determination of runs, eliminating the need for source image + bbox calculation in the inner loop. */ + +/* Determine a "run", such that the inverse affine of all pixels from + (x0, y) inclusive to (x1, y) exclusive fit within the bounds + of the source image. + + Initial values of x0, x1, and result values stored in first two + pointer arguments. +*/ + +#define EPSILON 1e-6 + +void +art_rgb_affine_run (int *p_x0, int *p_x1, int y, + int src_width, int src_height, + const double affine[6]) +{ + int x0, x1; + double z; + double x_intercept; + int xi; + + x0 = *p_x0; + x1 = *p_x1; + + /* do left and right edges */ + if (affine[0] > EPSILON) + { + z = affine[2] * (y + 0.5) + affine[4]; + x_intercept = -z / affine[0]; + xi = ceil (x_intercept + EPSILON - 0.5); + if (xi > x0) + x0 = xi; + x_intercept = (-z + src_width) / affine[0]; + xi = ceil (x_intercept - EPSILON - 0.5); + if (xi < x1) + x1 = xi; + } + else if (affine[0] < -EPSILON) + { + z = affine[2] * (y + 0.5) + affine[4]; + x_intercept = (-z + src_width) / affine[0]; + xi = ceil (x_intercept + EPSILON - 0.5); + if (xi > x0) + x0 = xi; + x_intercept = -z / affine[0]; + xi = ceil (x_intercept - EPSILON - 0.5); + if (xi < x1) + x1 = xi; + } + else + { + z = affine[2] * (y + 0.5) + affine[4]; + if (z < 0 || z >= src_width) + { + *p_x1 = *p_x0; + return; + } + } + + /* do top and bottom edges */ + if (affine[1] > EPSILON) + { + z = affine[3] * (y + 0.5) + affine[5]; + x_intercept = -z / affine[1]; + xi = ceil (x_intercept + EPSILON - 0.5); + if (xi > x0) + x0 = xi; + x_intercept = (-z + src_height) / affine[1]; + xi = ceil (x_intercept - EPSILON - 0.5); + if (xi < x1) + x1 = xi; + } + else if (affine[1] < -EPSILON) + { + z = affine[3] * (y + 0.5) + affine[5]; + x_intercept = (-z + src_height) / affine[1]; + xi = ceil (x_intercept + EPSILON - 0.5); + if (xi > x0) + x0 = xi; + x_intercept = -z / affine[1]; + xi = ceil (x_intercept - EPSILON - 0.5); + if (xi < x1) + x1 = xi; + } + else + { + z = affine[3] * (y + 0.5) + affine[5]; + if (z < 0 || z >= src_height) + { + *p_x1 = *p_x0; + return; + } + } + + *p_x0 = x0; + *p_x1 = x1; +} diff --git a/karbon/render/art_rgb_affine_private.h b/karbon/render/art_rgb_affine_private.h new file mode 100644 index 00000000..a2424999 --- /dev/null +++ b/karbon/render/art_rgb_affine_private.h @@ -0,0 +1,39 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ART_RGB_AFFINE_PRIVATE_H__ +#define __ART_RGB_AFFINE_PRIVATE_H__ + +/* This module handles compositing of affine-transformed rgb images + over rgb pixel buffers. */ + +#ifdef __cplusplus +extern "C" { +#endif + +void +art_rgb_affine_run (int *p_x0, int *p_x1, int y, + int src_width, int src_height, + const double affine[6]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/karbon/render/art_rgb_svp.c b/karbon/render/art_rgb_svp.c new file mode 100644 index 00000000..617f1abe --- /dev/null +++ b/karbon/render/art_rgb_svp.c @@ -0,0 +1,458 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* Render a sorted vector path into an RGB buffer. */ + +#include "config.h" +#include "art_rgb_svp.h" + +#include <libart_lgpl/art_svp.h> +#include <libart_lgpl/art_svp_render_aa.h> +#include "art_rgb.h" + +typedef struct _ArtRgbSVPData ArtRgbSVPData; +typedef struct _ArtRgbSVPAlphaData ArtRgbSVPAlphaData; + +struct _ArtRgbSVPData { + art_u32 rgbtab[256]; + art_u8 *buf; + int rowstride; + int x0, x1; +}; + +struct _ArtRgbSVPAlphaData { + int alphatab[256]; + art_u8 r, g, b, alpha; + art_u32 rgb; + art_u8 *buf; + int rowstride; + int x0, x1; +}; + +static void +art_rgb_svp_callback_ (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtRgbSVPData *data = (ArtRgbSVPData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + art_u32 rgb; + int x0, x1; + int k; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + if (n_steps > 0) + { + run_x1 = steps[0].x; + if (run_x1 > x0) + { + rgb = data->rgbtab[(running_sum >> 16) & 0xff]; +/* art_rgb_fill_run (linebuf, + rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff, + run_x1 - x0);*/ + } + + for (k = 0; k < n_steps - 1; k++) + { + running_sum += steps[k].delta; + run_x0 = run_x1; + run_x1 = steps[k + 1].x; + if (run_x1 > run_x0) + { + rgb = data->rgbtab[(running_sum >> 16) & 0xff]; +/* art_rgb_fill_run (linebuf + (run_x0 - x0) * 3, + rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff, + run_x1 - run_x0);*/ + } + } + running_sum += steps[k].delta; + if (x1 > run_x1) + { + rgb = data->rgbtab[(running_sum >> 16) & 0xff]; +/* art_rgb_fill_run (linebuf + (run_x1 - x0) * 3, + rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff, + x1 - run_x1);*/ + } + } + else + { + rgb = data->rgbtab[(running_sum >> 16) & 0xff]; +/* art_rgb_fill_run (linebuf, + rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff, + x1 - x0);*/ + } + + data->buf += data->rowstride; +} + +/* Render the vector path into the RGB buffer. */ + +/** + * art_rgb_svp_aa: Render sorted vector path into RGB buffer. + * @svp: The source sorted vector path. + * @x0: Left coordinate of destination rectangle. + * @y0: Top coordinate of destination rectangle. + * @x1: Right coordinate of destination rectangle. + * @y1: Bottom coordinate of destination rectangle. + * @fg_color: Foreground color in 0xRRGGBB format. + * @bg_color: Background color in 0xRRGGBB format. + * @buf: Destination RGB buffer. + * @rowstride: Rowstride of @buf buffer. + * @alphagamma: #ArtAlphaGamma for gamma-correcting the rendering. + * + * Renders the shape specified with @svp into the @buf RGB buffer. + * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height, + * of the rectangle rendered. The new pixels are stored starting at + * the first byte of @buf. Thus, the @x0 and @y0 parameters specify + * an offset within @svp, and may be tweaked as a way of doing + * integer-pixel translations without fiddling with @svp itself. + * + * The @fg_color and @bg_color arguments specify the opaque colors to + * be used for rendering. For pixels of entirely 0 winding-number, + * @bg_color is used. For pixels of entirely 1 winding number, + * @fg_color is used. In between, the color is interpolated based on + * the fraction of the pixel with a winding number of 1. If + * @alphagamma is NULL, then linear interpolation (in pixel counts) is + * the default. Otherwise, the interpolation is as specified by + * @alphagamma. + **/ +void +art_rgb_svp_aa_ (const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 fg_color, art_u32 bg_color, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma) +{ + ArtRgbSVPData data; + + int r_fg, g_fg, b_fg; + int r_bg, g_bg, b_bg; + int r, g, b; + int dr, dg, db; + int i; + + if (alphagamma == NULL) + { + r_fg = fg_color >> 16; + g_fg = (fg_color >> 8) & 0xff; + b_fg = fg_color & 0xff; + + r_bg = bg_color >> 16; + g_bg = (bg_color >> 8) & 0xff; + b_bg = bg_color & 0xff; + + r = (r_bg << 16) + 0x8000; + g = (g_bg << 16) + 0x8000; + b = (b_bg << 16) + 0x8000; + dr = ((r_fg - r_bg) << 16) / 255; + dg = ((g_fg - g_bg) << 16) / 255; + db = ((b_fg - b_bg) << 16) / 255; + + for (i = 0; i < 256; i++) + { + data.rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16); + r += dr; + g += dg; + b += db; + } + } + else + { + int *table; + art_u8 *invtab; + + table = alphagamma->table; + + r_fg = table[fg_color >> 16]; + g_fg = table[(fg_color >> 8) & 0xff]; + b_fg = table[fg_color & 0xff]; + + r_bg = table[bg_color >> 16]; + g_bg = table[(bg_color >> 8) & 0xff]; + b_bg = table[bg_color & 0xff]; + + r = (r_bg << 16) + 0x8000; + g = (g_bg << 16) + 0x8000; + b = (b_bg << 16) + 0x8000; + dr = ((r_fg - r_bg) << 16) / 255; + dg = ((g_fg - g_bg) << 16) / 255; + db = ((b_fg - b_bg) << 16) / 255; + + invtab = alphagamma->invtable; + for (i = 0; i < 256; i++) + { + data.rgbtab[i] = (invtab[r >> 16] << 16) | + (invtab[g >> 16] << 8) | + invtab[b >> 16]; + r += dr; + g += dg; + b += db; + } + } + data.buf = buf; + data.rowstride = rowstride; + data.x0 = x0; + data.x1 = x1; + art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_callback_, &data); +} + +static void +art_rgb_svp_alpha_callback_ (void *callback_data, int y, + int start, ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + art_u8 r, g, b; + int *alphatab; + int alpha; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + r = data->r; + g = data->g; + b = data->b; + alphatab = data->alphatab; + + if (n_steps > 0) + { + run_x1 = steps[0].x; + if (run_x1 > x0) + { + alpha = (running_sum >> 16) & 0xff; + if (alpha) + art_rgb_run_alpha_ (linebuf, + r, g, b, alphatab[alpha], + run_x1 - x0); + } + + for (k = 0; k < n_steps - 1; k++) + { + running_sum += steps[k].delta; + run_x0 = run_x1; + run_x1 = steps[k + 1].x; + if (run_x1 > run_x0) + { + alpha = (running_sum >> 16) & 0xff; + if (alpha) + art_rgb_run_alpha_ (linebuf + (run_x0 - x0) * 4, + r, g, b, alphatab[alpha], + run_x1 - run_x0); + } + } + running_sum += steps[k].delta; + if (x1 > run_x1) + { + alpha = (running_sum >> 16) & 0xff; + if (alpha) + art_rgb_run_alpha_ (linebuf + (run_x1 - x0) * 4, + r, g, b, alphatab[alpha], + x1 - run_x1); + } + } + else + { + alpha = (running_sum >> 16) & 0xff; + if (alpha) + art_rgb_run_alpha_ (linebuf, + r, g, b, alphatab[alpha], + x1 - x0); + } + + data->buf += data->rowstride; +} + +static void +art_rgb_svp_alpha_opaque_callback_ (void *callback_data, int y, + int start, + ArtSVPRenderAAStep *steps, int n_steps) +{ + ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data; + art_u8 *linebuf; + int run_x0, run_x1; + art_u32 running_sum = start; + int x0, x1; + int k; + art_u8 r, g, b; + art_u32 rgb; + int *alphatab; + int alpha; + + linebuf = data->buf; + x0 = data->x0; + x1 = data->x1; + + r = data->r; + g = data->g; + b = data->b; + rgb = data->rgb; + alphatab = data->alphatab; + + if (n_steps > 0) + { + run_x1 = steps[0].x; + if (run_x1 > x0) + { + alpha = running_sum >> 16; + if (alpha) + { + if (alpha >= 255) + art_rgb_fill_run_ (linebuf, + rgb, + run_x1 - x0); + else + art_rgb_run_alpha_ (linebuf, + r, g, b, alphatab[alpha], + run_x1 - x0); + } + } + + for (k = 0; k < n_steps - 1; k++) + { + running_sum += steps[k].delta; + run_x0 = run_x1; + run_x1 = steps[k + 1].x; + if (run_x1 > run_x0) + { + alpha = running_sum >> 16; + if (alpha) + { + if (alpha >= 255) + art_rgb_fill_run_ (linebuf + (run_x0 - x0) * 4, + rgb, + run_x1 - run_x0); + else + art_rgb_run_alpha_ (linebuf + (run_x0 - x0) * 4, + r, g, b, alphatab[alpha], + run_x1 - run_x0); + } + } + } + running_sum += steps[k].delta; + if (x1 > run_x1) + { + alpha = running_sum >> 16; + if (alpha) + { + if (alpha >= 255) + art_rgb_fill_run_ (linebuf + (run_x1 - x0) * 4, + rgb, + x1 - run_x1); + else + art_rgb_run_alpha_ (linebuf + (run_x1 - x0) * 4, + r, g, b, alphatab[alpha], + x1 - run_x1); + } + } + } + else + { + alpha = running_sum >> 16; + if (alpha) + { + if (alpha >= 255) + art_rgb_fill_run_ (linebuf, + rgb, + x1 - x0); + else + art_rgb_run_alpha_ (linebuf, + r, g, b, alphatab[alpha], + x1 - x0); + } + } + data->buf += data->rowstride; +} + +/** + * art_rgb_svp_alpha: Alpha-composite sorted vector path over RGB buffer. + * @svp: The source sorted vector path. + * @x0: Left coordinate of destination rectangle. + * @y0: Top coordinate of destination rectangle. + * @x1: Right coordinate of destination rectangle. + * @y1: Bottom coordinate of destination rectangle. + * @rgba: Color in 0xRRGGBBAA format. + * @buf: Destination RGB buffer. + * @rowstride: Rowstride of @buf buffer. + * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing. + * + * Renders the shape specified with @svp over the @buf RGB buffer. + * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height, + * of the rectangle rendered. The new pixels are stored starting at + * the first byte of @buf. Thus, the @x0 and @y0 parameters specify + * an offset within @svp, and may be tweaked as a way of doing + * integer-pixel translations without fiddling with @svp itself. + * + * The @rgba argument specifies the color for the rendering. Pixels of + * entirely 0 winding number are left untouched. Pixels of entirely + * 1 winding number have the color @rgba composited over them (ie, + * are replaced by the red, green, blue components of @rgba if the alpha + * component is 0xff). Pixels of intermediate coverage are interpolated + * according to the rule in @alphagamma, or default to linear if + * @alphagamma is NULL. + **/ +void +art_rgb_svp_alpha_ (const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgb, int alpha, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma) +{ + ArtRgbSVPAlphaData data; + int r, g, b; + int i; + int a, da; + + r = (rgb >> 16) & 0xff; + g = (rgb >> 8) & 0xff; + b = rgb & 0xff; + + data.r = r; + data.g = g; + data.b = b; + data.alpha = alpha; + data.rgb = rgb; + + a = 0x8000; + da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */ + + for (i = 0; i < 256; i++) + { + data.alphatab[i] = a >> 16; + a += da; + } + + data.buf = buf; + data.rowstride = rowstride; + data.x0 = x0; + data.x1 = x1; + if (alpha == 255) + art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_opaque_callback_, + &data); + else + art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_callback_, &data); +} diff --git a/karbon/render/art_rgb_svp.h b/karbon/render/art_rgb_svp.h new file mode 100644 index 00000000..77b32dd9 --- /dev/null +++ b/karbon/render/art_rgb_svp.h @@ -0,0 +1,55 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ART_RGB_SVP_H__ +#define __ART_RGB_SVP_H__ + +/* Render a sorted vector path into an RGB buffer. */ + +#ifdef LIBART_COMPILATION +#include "art_alphagamma.h" +#include "art_svp.h" +#else +#include <libart_lgpl/art_alphagamma.h> +#include <libart_lgpl/art_svp.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void +art_rgb_svp_aa_ (const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 fg_color, art_u32 bg_color, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma); + +void +art_rgb_svp_alpha_ (const ArtSVP *svp, + int x0, int y0, int x1, int y1, + art_u32 rgb, int alpha, + art_u8 *buf, int rowstride, + ArtAlphaGamma *alphagamma); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ART_RGB_SVP_H__ */ diff --git a/karbon/render/art_rgba_affine.c b/karbon/render/art_rgba_affine.c new file mode 100644 index 00000000..9ff88d5f --- /dev/null +++ b/karbon/render/art_rgba_affine.c @@ -0,0 +1,107 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "art_rgba_affine.h" + +#include <math.h> +#include <libart_lgpl/art_misc.h> +#include <libart_lgpl/art_point.h> +#include <libart_lgpl/art_affine.h> +#include <art_rgb_affine_private.h> + +/* This module handles compositing of affine-transformed rgb images + over rgb pixel buffers. */ + +/** + * art_rgb_affine: Affine transform source RGB image and composite. + * @dst: Destination image RGB buffer. + * @x0: Left coordinate of destination rectangle. + * @y0: Top coordinate of destination rectangle. + * @x1: Right coordinate of destination rectangle. + * @y1: Bottom coordinate of destination rectangle. + * @dst_rowstride: Rowstride of @dst buffer. + * @src: Source image RGB buffer. + * @src_width: Width of source image. + * @src_height: Height of source image. + * @src_rowstride: Rowstride of @src buffer. + * @affine: Affine transform. + * @level: Filter level. + * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing. + * + * Affine transform the source image stored in @src, compositing over + * the area of destination image @dst specified by the rectangle + * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges + * of this rectangle are included, and the right and bottom edges are + * excluded. + * + * The @alphagamma parameter specifies that the alpha compositing be done + * in a gamma-corrected color space. Since the source image is opaque RGB, + * this argument only affects the edges. In the current implementation, + * it is ignored. + * + * The @level parameter specifies the speed/quality tradeoff of the + * image interpolation. Currently, only ART_FILTER_NEAREST is + * implemented. + **/ +void +art_rgba_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + ArtFilterLevel level, + ArtAlphaGamma *alphagamma) +{ + /* Note: this is a slow implementation, and is missing all filter + levels other than NEAREST. It is here for clarity of presentation + and to establish the interface. */ + int x, y; + double inv[6]; + art_u8 *dst_p, *dst_linestart; + const art_u8 *src_p; + ArtPoint pt, src_pt; + int src_x, src_y; + int run_x0, run_x1; + + dst_linestart = dst; + art_affine_invert (inv, affine); + for (y = y0; y < y1; y++) + { + pt.y = y + 0.5; + run_x0 = x0; + run_x1 = x1; + art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height, + inv); + dst_p = dst_linestart + (run_x0 - x0) * 4; + for (x = run_x0; x < run_x1; x++) + { + pt.x = x + 0.5; + art_affine_point (&src_pt, &pt, inv); + src_x = floor (src_pt.x); + src_y = floor (src_pt.y); + src_p = src + (src_y * src_rowstride) + src_x * 4; + dst_p[0] = src_p[0]; + dst_p[1] = src_p[1]; + dst_p[2] = src_p[2]; + dst_p[3] = src_p[3]; + dst_p += 4; + } + dst_linestart += dst_rowstride; + } +} diff --git a/karbon/render/art_rgba_affine.h b/karbon/render/art_rgba_affine.h new file mode 100644 index 00000000..3403691b --- /dev/null +++ b/karbon/render/art_rgba_affine.h @@ -0,0 +1,50 @@ +/* Libart_LGPL - library of basic graphic primitives + * Copyright (C) 1998 Raph Levien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ART_RGB_AFFINE_H__ +#define __ART_RGB_AFFINE_H__ + +/* This module handles compositing of affine-transformed rgb images + over rgb pixel buffers. */ + +#ifdef LIBART_COMPILATION +#include "art_filterlevel.h" +#include "art_alphagamma.h" +#else +#include <libart_lgpl/art_filterlevel.h> +#include <libart_lgpl/art_alphagamma.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void +art_rgba_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, + const art_u8 *src, + int src_width, int src_height, int src_rowstride, + const double affine[6], + ArtFilterLevel level, + ArtAlphaGamma *alphagamma); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/karbon/render/vkopainter.cc b/karbon/render/vkopainter.cc new file mode 100644 index 00000000..21ab911c --- /dev/null +++ b/karbon/render/vkopainter.cc @@ -0,0 +1,943 @@ +/* This file is part of the KDE project. + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +// kopainter/libart wrapper + +#include "vkopainter.h" +#include "vstroke.h" +#include "vfill.h" +#include "vcolor.h" +#include "vpattern.h" + +#include <qpaintdevice.h> +#include <qpixmap.h> +#include <qpointarray.h> +#include <qimage.h> + +#include "libart_lgpl/art_vpath.h" +#include <libart_lgpl/art_bpath.h> +#include <libart_lgpl/art_vpath_bpath.h> +#include <libart_lgpl/art_svp_vpath.h> +#include <libart_lgpl/art_svp_vpath_stroke.h> +#include <libart_lgpl/art_svp.h> +#include <libart_lgpl/art_svp_ops.h> +#include <libart_lgpl/art_affine.h> +#include <libart_lgpl/art_svp_intersect.h> +#include <libart_lgpl/art_rect_svp.h> +#include <libart_lgpl/art_pathcode.h> +#include <libart_lgpl/art_vpath_dash.h> +#include "art_rgba_affine.h" +#include "art_render_misc.h" +#include <libart_lgpl/art_render_svp.h> + +#include "art_rgb_svp.h" +#include "art_render_pattern.h" + +#include <X11/Xlib.h> + +#include <gdk-pixbuf-xlibrgb.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <math.h> + +#include <KoPoint.h> +#include <KoRect.h> +#include <karbon_factory.h> +#include <karbon_resourceserver.h> + + +#define INITIAL_ALLOC 300 +#define ALLOC_INCREMENT 100 + +VKoPainter::VKoPainter( QPaintDevice *target, unsigned int w, unsigned int h, bool bDrawNodes ) +: VPainter( target, w, h ), m_target( target ), m_bDrawNodes( bDrawNodes ) +{ + //kdDebug(38000) << "w : " << w << endl; + //kdDebug(38000) << "h : " << h << endl; + m_width = w;//( w > 0 ) ? w : target->width(); + m_height= h;//( h > 0 ) ? h : target->height(); + m_buffer = 0L; + m_path = 0L; + m_index = 0; + resize( m_width, m_height ); + clear(); + m_clipPaths.setAutoDelete( false ); + + m_stroke = 0L; + m_fill = 0L; + m_fillRule = evenOdd; + + xlib_rgb_init_with_depth( target->x11Display(), XScreenOfDisplay( target->x11Display(), + target->x11Screen() ), target->x11Depth() ); + + gc = XCreateGC( target->x11Display(), target->handle(), 0, 0 ); + + m_zoomFactor = 1; +} + +VKoPainter::VKoPainter( unsigned char *buffer, unsigned int w, unsigned int h, bool bDrawNodes ) +: VPainter( 0L, w, h ), m_buffer( buffer ), m_bDrawNodes( bDrawNodes ) +{ + //kdDebug(38000) << "w : " << w << endl; + //kdDebug(38000) << "h : " << h << endl; + m_target = 0L; + m_width = w; + m_height= h; + m_path = 0L; + m_index = 0; + clear(); + m_clipPaths.setAutoDelete( false ); + + m_stroke = 0L; + m_fill = 0L; + + gc = 0L; + + m_zoomFactor = 1; +} + +VKoPainter::~VKoPainter() +{ + // If we are in target mode, we created a buffer, else if we used the other ctor + // we didn't. + if( m_target ) + art_free( m_buffer ); + + delete m_stroke; + delete m_fill; + if( m_path ) + art_free( m_path ); + + if( gc ) + XFreeGC( m_target->x11Display(), gc ); +} + +void +VKoPainter::resize( unsigned int w, unsigned int h ) +{ + if( !m_buffer || w != m_width || h != m_height ) + { + // TODO : realloc? + art_free( m_buffer ); + m_buffer = 0; + m_width = w; + m_height = h; + if ( m_width != 0 && m_height != 0 ) + m_buffer = art_new( art_u8, m_width * m_height * 4 ); + clear(); + } +} + +void +VKoPainter::begin() +{ +} + +void +VKoPainter::end() +{ + //xlib_draw_rgb_image( m_target->handle(), gc, 0, 0, m_width, m_height, + // XLIB_RGB_DITHER_NONE, m_buffer, m_width * 4 ); + xlib_draw_rgb_32_image( m_target->handle(), gc, 0, 0, m_width, m_height, + XLIB_RGB_DITHER_NONE, m_buffer, m_width * 4 ); + /*xlib_draw_rgb_image( pix.handle(), gc, 0, 0, m_width, m_height, + XLIB_RGB_DITHER_NONE, m_buffer, m_width * 3 ); + bitBlt( m_target, 0, 0, &pix, 0, 0, m_width, m_height );*/ +} + +void +VKoPainter::blit( const KoRect &r ) +{ + //kdDebug(38000) << "m_width : " << m_width << endl; + //kdDebug(38000) << "m_height : " << m_height << endl; + int x = KMAX( 0, int( r.x() ) ); + int y = KMAX( 0, int( r.y() ) ); + int width = KMIN( m_width, (unsigned int)KMAX( 0, int( r.x() + r.width() ) ) ); + int height = KMIN( m_height, (unsigned int)KMAX( 0, int( r.y() + r.height() ) ) ); + xlib_draw_rgb_32_image( m_target->handle(), gc, x, y, width - x, height - y, + XLIB_RGB_DITHER_NONE, m_buffer + (x * 4) + (y * m_width * 4), m_width * 4 ); +} + +void +VKoPainter::clear() +{ + if( m_buffer ) + memset( m_buffer, qRgba( 255, 255, 255, 255 ), m_width * m_height * 4 ); +} + +void +VKoPainter::clear( const QColor &c ) +{ + if( m_buffer ) + memset( m_buffer, c.rgb(), m_width * m_height * 4 ); +} + +void +VKoPainter::clear( const KoRect &r, const QColor &c ) +{ + unsigned int color = c.rgb(); + int x = KMAX( 0, int( r.x() ) ); + int y = KMAX( 0, int( r.y() ) ); + int width = KMIN( m_width, (unsigned int)KMAX( 0, int( r.x() + r.width() ) ) ); + int height = KMIN( m_height, (unsigned int)KMAX( 0, int( r.y() + r.height() ) ) ); + if( m_buffer ) + { + for( int i = y;i < height;i++) + memset( m_buffer + int( x * 4) + int( i * ( m_width * 4 ) ), + qRgba( qRed( color ), qGreen( color ), qBlue( color ), 100 ), int( width * 4 ) ); + } +} + +void +VKoPainter::setWorldMatrix( const QWMatrix &mat ) +{ + m_matrix = mat; +} + +void +VKoPainter::setZoomFactor( double zoomFactor ) +{ + m_zoomFactor = zoomFactor; +} + +void +VKoPainter::ensureSpace( unsigned int newindex ) +{ + if( m_index == 0 ) + { + if( !m_path ) + m_path = art_new( ArtBpath, INITIAL_ALLOC ); + m_alloccount = INITIAL_ALLOC; + } + else if( newindex > m_alloccount ) + { + m_alloccount += ALLOC_INCREMENT; + m_path = art_renew( m_path, ArtBpath, m_alloccount ); + } +} + +void +VKoPainter::moveTo( const KoPoint &p ) +{ + ensureSpace( m_index + 1 ); + + m_path[ m_index ].code = ART_MOVETO; + + m_path[ m_index ].x3 = p.x() * m_zoomFactor; + m_path[ m_index ].y3 = p.y() * m_zoomFactor; + + m_index++; +} + +void +VKoPainter::lineTo( const KoPoint &p ) +{ + ensureSpace( m_index + 1 ); + + m_path[ m_index ].code = ART_LINETO; + m_path[ m_index ].x3 = p.x() * m_zoomFactor; + m_path[ m_index ].y3 = p.y() * m_zoomFactor; + + m_index++; +} + +void +VKoPainter::curveTo( const KoPoint &p1, const KoPoint &p2, const KoPoint &p3 ) +{ + ensureSpace( m_index + 1 ); + + m_path[ m_index ].code = ART_CURVETO; + m_path[ m_index ].x1 = p1.x() * m_zoomFactor; + m_path[ m_index ].y1 = p1.y() * m_zoomFactor; + m_path[ m_index ].x2 = p2.x() * m_zoomFactor; + m_path[ m_index ].y2 = p2.y() * m_zoomFactor; + m_path[ m_index ].x3 = p3.x() * m_zoomFactor; + m_path[ m_index ].y3 = p3.y() * m_zoomFactor; + + m_index++; +} + +void +VKoPainter::newPath() +{ + m_index = 0; +} + +void +VKoPainter::setFillRule( VFillRule fillRule ) +{ + m_fillRule = fillRule; +} + +void +VKoPainter::fillPath() +{ + if( m_index == 0 ) return; + + // find begin of last subpath + int find = -1; + for( int i = m_index - 1; i >= 0; i-- ) + { + if( m_path[i].code == ART_MOVETO_OPEN || m_path[i].code == ART_MOVETO ) + { + find = i; + break; + } + } + + // for now, always close + if( find != -1 && ( m_path[ find ].x3 != m_path[ m_index - 1 ].x3 || + m_path[ find ].y3 != m_path[ m_index - 1 ].y3 ) ) + { + ensureSpace( m_index + 1 ); + + m_path[ m_index ].code = ART_LINETO; + m_path[ m_index ].x3 = m_path[ find ].x3; + m_path[ m_index ].y3 = m_path[ find ].y3; + + m_index++; + m_path[ m_index ].code = ART_END; + } + else + m_path[ m_index++ ].code = ART_END; + + if( m_fill && m_fill->type() != VFill::none ) + { + ArtVpath *path = art_bez_path_to_vec( m_path , 0.25 ); + drawVPath( path ); + } + + m_index--; +} + +void +VKoPainter::strokePath() +{ + if( m_index == 0 ) return; + + if( m_stroke && m_stroke->lineWidth() == 0 ) + return; + if( m_path[ m_index ].code != ART_END) + m_path[ m_index ].code = ART_END; + + ArtVpath *path = art_bez_path_to_vec( m_path , 0.25 ); + + drawVPath( path ); +} + +void +VKoPainter::setClipPath() +{ + ArtVpath *path; + path = art_bez_path_to_vec( m_path , 0.25 ); + m_clipPaths.append( art_svp_from_vpath( path ) ); + art_free( path ); +} + +void +VKoPainter::resetClipPath() +{ + art_svp_free( m_clipPaths.current() ); + m_clipPaths.remove(); +} + +void +VKoPainter::setPen( const VStroke &stroke ) +{ + delete m_stroke; + m_stroke = new VStroke; + *m_stroke = stroke; +} + +void +VKoPainter::setPen( const QColor &c ) +{ + delete m_stroke; + m_stroke = new VStroke; + + float r = static_cast<float>( c.red() ) / 255.0; + float g = static_cast<float>( c.green() ) / 255.0; + float b = static_cast<float>( c.blue() ) / 255.0; + + VColor color; + color.set( r, g, b ); + m_stroke->setColor( color ); +} + +void +VKoPainter::setPen( Qt::PenStyle style ) +{ + if( style == Qt::NoPen ) + { + delete m_stroke; + m_stroke = 0L; + } +} + +void +VKoPainter::setBrush( const QColor &c ) +{ + delete m_fill; + m_fill = new VFill; + + float r = static_cast<float>( c.red() ) / 255.0; + float g = static_cast<float>( c.green() ) / 255.0; + float b = static_cast<float>( c.blue() ) / 255.0; + + VColor color; + color.set( r, g, b ); + m_fill->setColor( color ); +} + +void +VKoPainter::setBrush( Qt::BrushStyle style ) +{ + if( style == Qt::NoBrush ) + { + delete m_fill; + m_fill = 0L; + } +} + +void +VKoPainter::setBrush( const VFill &fill ) +{ + delete m_fill; + m_fill = new VFill; + *m_fill = fill; +} + +void +VKoPainter::save() +{ +} + +void +VKoPainter::restore() +{ +} + +void +VKoPainter::setRasterOp( Qt::RasterOp ) +{ +} + +void +VKoPainter::clampToViewport( int &x0, int &y0, int &x1, int &y1 ) +{ + // clamp to viewport + x0 = kMax( x0, 0 ); + x0 = kMin( x0, int( m_width ) ); + y0 = kMax( y0, 0 ); + y0 = kMin( y0, int ( m_height ) ); + x1 = kMax( x1, 0 ); + x1 = kMin( x1, int( m_width ) ); + y1 = kMax( y1, 0 ); + y1 = kMin( y1, int( m_height ) ); +} + +void +VKoPainter::clampToViewport( const ArtSVP &svp, int &x0, int &y0, int &x1, int &y1 ) +{ + // get SVP bbox + ArtDRect bbox; + art_drect_svp( &bbox, &svp ); + // Remove comments if we really decide for SVP bbox usage + //m_bbox = KoRect( bbox.x0, bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0 ); + + // clamp to viewport + x0 = int( bbox.x0 ); + x0 = kMax( x0, 0 ); + x0 = kMin( x0, int( m_width ) ); + y0 = int( bbox.y0 ); + y0 = kMax( y0, 0 ); + y0 = kMin( y0, int ( m_height ) ); + x1 = int( bbox.x1 ) + 1; + x1 = kMax( x1, 0 ); + x1 = kMin( x1, int( m_width ) ); + y1 = int( bbox.y1 ) + 1; + y1 = kMax( y1, 0 ); + y1 = kMin( y1, int( m_height ) ); +} + +void +VKoPainter::drawVPath( ArtVpath *vec ) +{ + ArtSVP *strokeSvp = 0L; + ArtSVP *fillSvp = 0L; + + // set up world matrix + double affine[6]; + affine[0] = m_matrix.m11(); + affine[1] = 0;//m_matrix.m12(); + affine[2] = 0;//m_matrix.m21(); + affine[3] = m_matrix.m22(); + affine[4] = m_matrix.dx(); + affine[5] = m_matrix.dy(); + ArtVpath *temp = art_vpath_affine_transform( vec, affine ); + art_free( vec ); + vec = temp; + + int af = 0; + int as = 0; + art_u32 fillColor = 0; + + // filling + QColor color; + if( m_fill && m_fill->type() != VFill::none ) + { + color = m_fill->color(); + af = qRound( 255 * m_fill->color().opacity() ); + fillColor = ( 0 << 24 ) | ( color.blue() << 16 ) | ( color.green() << 8 ) | color.red(); + + ArtSvpWriter *swr; + ArtSVP *temp; + temp = art_svp_from_vpath( vec ); + + if( m_fillRule == evenOdd ) + swr = art_svp_writer_rewind_new( ART_WIND_RULE_ODDEVEN ); + else + swr = art_svp_writer_rewind_new( ART_WIND_RULE_NONZERO ); + + art_svp_intersector( temp, swr ); + fillSvp = art_svp_writer_rewind_reap( swr ); + + art_svp_free( temp ); + } + + art_u32 strokeColor = 0; + // stroke + if( m_stroke && m_stroke->type() != VStroke::none ) + { + ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT; + ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER; + // TODO : non rgb support ? + + color = m_stroke->color(); + as = qRound( 255 * m_stroke->color().opacity() ); + strokeColor = ( 0 << 24 ) | ( color.blue() << 16 ) | ( color.green() << 8 ) | color.red(); + + double ratio = m_zoomFactor;//sqrt(pow(affine[0], 2) + pow(affine[3], 2)) / sqrt(2); + if( m_stroke->dashPattern().array().count() > 0 ) + { + // there are dashes to be rendered + ArtVpathDash dash; + dash.offset = m_stroke->dashPattern().offset() * ratio; + dash.n_dash = m_stroke->dashPattern().array().count(); + double *dashes = new double[ dash.n_dash ]; + for( int i = 0; i < dash.n_dash; i++ ) + dashes[i] = m_stroke->dashPattern().array()[i] * ratio; + + dash.dash = dashes; + // get the dashed VPath and use that for the stroke render operation + ArtVpath *vec2 = art_vpath_dash( vec, &dash ); + art_free( vec ); + + vec = vec2; + delete [] dashes; + } + // caps translation karbon -> art + if( m_stroke->lineCap() == VStroke::capRound ) + capStyle = ART_PATH_STROKE_CAP_ROUND; + else if( m_stroke->lineCap() == VStroke::capSquare ) + capStyle = ART_PATH_STROKE_CAP_SQUARE; + + // join translation karbon -> art + if( m_stroke->lineJoin() == VStroke::joinRound ) + joinStyle = ART_PATH_STROKE_JOIN_ROUND; + else if( m_stroke->lineJoin() == VStroke::joinBevel ) + joinStyle = ART_PATH_STROKE_JOIN_BEVEL; + + // zoom stroke width; + strokeSvp = art_svp_vpath_stroke( vec, joinStyle, capStyle, ratio * m_stroke->lineWidth(), m_stroke->miterLimit(), 0.25 ); + } + + int x0, y0, x1, y1; + + // render the svp to the buffer + if( strokeSvp ) + { + if( m_stroke && m_stroke->type() == VStroke::grad ) + applyGradient( strokeSvp, false ); + else if( m_stroke && m_stroke->type() == VStroke::patt ) + applyPattern( strokeSvp, false ); + else + { + clampToViewport( *strokeSvp, x0, y0, x1, y1 ); + if( x0 != x1 && y0 != y1 ) + art_rgb_svp_alpha_( strokeSvp, x0, y0, x1, y1, strokeColor, as, m_buffer + x0 * 4 + y0 * m_width * 4, m_width * 4, 0 ); + } + art_svp_free( strokeSvp ); + } + + if( fillSvp ) + { + if( m_fill && m_fill->type() == VFill::grad ) + applyGradient( fillSvp, true ); + else if( m_fill && m_fill->type() == VFill::patt ) + applyPattern( fillSvp, true ); + else + { + clampToViewport( *fillSvp, x0, y0, x1, y1 ); + if( x0 != x1 && y0 != y1 ) + art_rgb_svp_alpha_( fillSvp, x0, y0, x1, y1, fillColor, af, m_buffer + x0 * 4 + y0 * m_width * 4, m_width * 4, 0 ); + } + art_svp_free( fillSvp ); + } + + //delete m_stroke; + //m_stroke = 0L; + //delete m_fill; + //m_fill = 0L; + + art_free( vec ); +} + +void +VKoPainter::applyPattern( ArtSVP *svp, bool fill ) +{ + if(!svp) { + return; + } + + int x0, y0, x1, y1; + clampToViewport( *svp, x0, y0, x1, y1 ); + + ArtRender *render = 0L; + + VPattern pat = fill ? m_fill->pattern() : m_stroke->pattern(); + if( !pat.isValid() ) { + pat.load( KGlobal::iconLoader()->iconPath( "karbon.png", -KIcon::SizeMedium ) ); } + if( !pat.isValid() ) { + pat = *(dynamic_cast<VPattern *>(KarbonFactory::rServer()->patterns().getFirst() )) ;} + + ArtPattern *pattern = art_new( ArtPattern, 1 ); + + double dx = ( pat.vector().x() - pat.origin().x() ) * m_zoomFactor; + double dy = ( pat.vector().y() - pat.origin().y() ) * m_zoomFactor; + + pattern->twidth = pat.tileWidth(); + pattern->theight = pat.tileHeight(); + pattern->buffer = pat.pixels(); + pattern->opacity = fill ? short( m_fill->color().opacity() * 255.0 ) : short( m_stroke->color().opacity() * 255.0 ); + pattern->angle = atan2( -dy, dx ); + + if( x0 != x1 && y0 != y1 ) + { + render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * int(x0) + m_width * 4 * int(y0), m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 ); + art_render_svp( render, svp ); + art_render_pattern( render, pattern, ART_FILTER_HYPER ); + } + + if( render ) + art_render_invoke( render ); + art_free( pattern ); +} + +void +VKoPainter::applyGradient( ArtSVP *svp, bool fill ) +{ + int x0, y0, x1, y1; + clampToViewport( *svp, x0, y0, x1, y1 ); + + ArtRender *render = 0L; + + VGradient gradient = fill ? m_fill->gradient() : m_stroke->gradient(); + float opa = fill ? m_fill->color().opacity() : m_stroke->color().opacity(); + + if( gradient.type() == VGradient::linear ) + { + ArtGradientLinear *linear = art_new( ArtGradientLinear, 1 ); + + // TODO : make variable + if( gradient.repeatMethod() == VGradient::none ) + linear->spread = ART_GRADIENT_PAD; + else if( gradient.repeatMethod() == VGradient::repeat ) + linear->spread = ART_GRADIENT_REPEAT; + else if( gradient.repeatMethod() == VGradient::reflect ) + linear->spread = ART_GRADIENT_REFLECT; + + double _x1 = gradient.origin().x(); + double _x2 = gradient.vector().x(); + double _y2 = gradient.origin().y(); + double _y1 = gradient.vector().y(); + + double dx = ( _x2 - _x1 ) * m_zoomFactor; + _y1 = m_matrix.m22() * _y1 + m_matrix.dy() / m_zoomFactor; + _y2 = m_matrix.m22() * _y2 + m_matrix.dy() / m_zoomFactor; + double dy = ( _y1 - _y2 ) * m_zoomFactor; + double scale = 1.0 / ( dx * dx + dy * dy ); + + linear->a = dx * scale; + linear->b = dy * scale; + linear->c = -( ( _x1 * m_zoomFactor + m_matrix.dx() ) * linear->a + + ( _y2 * m_zoomFactor ) * linear->b ); + + // get stop array + int offsets = -1; + linear->stops = buildStopArray( gradient, offsets ); + linear->n_stops = offsets; + + if( x0 != x1 && y0 != y1 && offsets >= 0 ) + { + render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * int(x0) + m_width * 4 * int(y0), m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 ); + int opacity = int( opa * 255.0 ); + art_render_svp( render, svp ); + art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7)); + art_karbon_render_gradient_linear( render, linear, ART_FILTER_NEAREST ); + art_render_invoke( render ); + } + art_free( linear->stops ); + art_free( linear ); + } + else if( gradient.type() == VGradient::radial ) + { + ArtGradientRadial *radial = art_new( ArtGradientRadial, 1 ); + + // TODO : make variable + if( gradient.repeatMethod() == VGradient::none ) + radial->spread = ART_GRADIENT_PAD; + else if( gradient.repeatMethod() == VGradient::repeat ) + radial->spread = ART_GRADIENT_REPEAT; + else if( gradient.repeatMethod() == VGradient::reflect ) + radial->spread = ART_GRADIENT_REFLECT; + + radial->affine[0] = m_matrix.m11(); + radial->affine[1] = m_matrix.m12(); + radial->affine[2] = m_matrix.m21(); + radial->affine[3] = m_matrix.m22(); + radial->affine[4] = m_matrix.dx(); + radial->affine[5] = m_matrix.dy(); + + double cx = gradient.origin().x() * m_zoomFactor; + double cy = gradient.origin().y() * m_zoomFactor; + double fx = gradient.focalPoint().x() * m_zoomFactor; + double fy = gradient.focalPoint().y() * m_zoomFactor; + double r = sqrt( pow( gradient.vector().x() - gradient.origin().x(), 2 ) + + pow( gradient.vector().y() - gradient.origin().y(), 2 ) ); + r *= m_zoomFactor; + + radial->fx = (fx - cx) / r; + radial->fy = (fy - cy) / r; + + double aff1[6], aff2[6]; + art_affine_scale( aff1, r, r); + art_affine_translate( aff2, cx, cy ); + art_affine_multiply( aff1, aff1, aff2 ); + art_affine_multiply( aff1, aff1, radial->affine ); + art_affine_invert( radial->affine, aff1 ); + + // get stop array + int offsets = -1; + radial->stops = buildStopArray( gradient, offsets ); + radial->n_stops = offsets; + + if( x0 != x1 && y0 != y1 && offsets >= 0 ) + { + render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * x0 + m_width * 4 * y0, m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 ); + int opacity = int( opa * 255.0 ); + art_render_svp( render, svp ); + art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7)); + art_karbon_render_gradient_radial( render, radial, ART_FILTER_NEAREST ); + art_render_invoke( render ); + } + art_free( radial->stops ); + art_free( radial ); + } + else if( gradient.type() == VGradient::conic ) + { + ArtGradientConical *conical = art_new( ArtGradientConical, 1 ); + + // TODO : make variable + if( gradient.repeatMethod() == VGradient::none ) + conical->spread = ART_GRADIENT_PAD; + else if( gradient.repeatMethod() == VGradient::repeat ) + conical->spread = ART_GRADIENT_REPEAT; + else if( gradient.repeatMethod() == VGradient::reflect ) + conical->spread = ART_GRADIENT_REFLECT; + + double cx = gradient.origin().x() * m_zoomFactor; + cx = m_matrix.m11() * cx + m_matrix.dx(); + double cy = gradient.origin().y() * m_zoomFactor; + cy = m_matrix.m22() * cy + m_matrix.dy(); + double r = sqrt( pow( gradient.vector().x() - gradient.origin().x(), 2 ) + + pow( gradient.vector().y() - gradient.origin().y(), 2 ) ); + r *= m_zoomFactor; + + conical->cx = cx; + conical->cy = cy; + conical->r = r; + + // get stop array + int offsets = -1; + conical->stops = buildStopArray( gradient, offsets ); + conical->n_stops = offsets; + + if( x0 != x1 && y0 != y1 && offsets >= 0 ) + { + render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * x0 + m_width * 4 * y0, m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 ); + int opacity = int( opa * 255.0 ); + art_render_svp( render, svp ); + art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7)); + art_karbon_render_gradient_conical( render, conical, ART_FILTER_NEAREST ); + art_render_invoke( render ); + } + art_free( conical->stops ); + art_free( conical ); + } +} + +ArtGradientStop * +VKoPainter::buildStopArray( VGradient &gradient, int &offsets ) +{ + // TODO : make this generic + QPtrVector<VColorStop> colorStops = gradient.colorStops(); + offsets = colorStops.count(); + + ArtGradientStop *stopArray = art_new( ArtGradientStop, offsets * 2 - 1 ); + + for( int offset = 0 ; offset < offsets ; offset++ ) + { + double ramp = colorStops[ offset ]->rampPoint; + //double mid = colorStops[ offset ]->midPoint; + stopArray[ offset * 2 ].offset = ramp; + + QColor qStopColor = colorStops[ offset ]->color; + int r = qRed( qStopColor.rgb() ); + int g = qGreen( qStopColor.rgb() ); + int b = qBlue( qStopColor.rgb() ); + art_u32 rgba = (r << 24) | (g << 16) | (b << 8) | qAlpha(qStopColor.rgb()); + /* convert from separated to premultiplied alpha */ + int a = int( colorStops[ offset]->color.opacity() * 255.0 ); + r = (rgba >> 24) * a + 0x80; + r = (r + (r >> 8)) >> 8; + g = ((rgba >> 16) & 0xff) * a + 0x80; + g = (g + (g >> 8)) >> 8; + b = ((rgba >> 8) & 0xff) * a + 0x80; + b = (b + (b >> 8)) >> 8; + stopArray[ offset * 2 ].color[ 0 ] = ART_PIX_MAX_FROM_8(r); + stopArray[ offset * 2 ].color[ 1 ] = ART_PIX_MAX_FROM_8(g); + stopArray[ offset * 2 ].color[ 2 ] = ART_PIX_MAX_FROM_8(b); + stopArray[ offset * 2 ].color[ 3 ] = ART_PIX_MAX_FROM_8(a); + + if( offset + 1 != offsets ) + { + stopArray[ offset * 2 + 1 ].offset = ramp + ( colorStops[ offset + 1 ]->rampPoint - ramp ) * colorStops[ offset ]->midPoint; + + QColor qStopColor2 = colorStops[ offset + 1 ]->color; + rgba = int(r + ((qRed(qStopColor2.rgb()) - r)) * 0.5) << 24 | + int(g + ((qGreen(qStopColor2.rgb()) - g)) * 0.5) << 16 | + int(b + ((qBlue(qStopColor2.rgb()) - b)) * 0.5) << 8 | + qAlpha(qStopColor2.rgb()); + /* convert from separated to premultiplied alpha */ + int a = int( colorStops[ offset]->color.opacity() * 255.0 ); + r = (rgba >> 24) * a + 0x80; + r = (r + (r >> 8)) >> 8; + g = ((rgba >> 16) & 0xff) * a + 0x80; + g = (g + (g >> 8)) >> 8; + b = ((rgba >> 8) & 0xff) * a + 0x80; + b = (b + (b >> 8)) >> 8; + stopArray[ offset * 2 + 1 ].color[ 0 ] = ART_PIX_MAX_FROM_8(r); + stopArray[ offset * 2 + 1 ].color[ 1 ] = ART_PIX_MAX_FROM_8(g); + stopArray[ offset * 2 + 1 ].color[ 2 ] = ART_PIX_MAX_FROM_8(b); + stopArray[ offset * 2 + 1 ].color[ 3 ] = ART_PIX_MAX_FROM_8(a); + } + } + + offsets = offsets * 2 - 1; + return stopArray; +} + +void +VKoPainter::drawNode( const KoPoint& p, int width ) +{ + if( !m_bDrawNodes ) return; + + KoPoint _p( m_matrix.map( QPoint( int( p.x() * m_zoomFactor ), int( p.y() * m_zoomFactor ) ) ) ); + int x1 = int( _p.x() - width ); + int x2 = int( _p.x() + width ); + int y1 = int( _p.y() - width ); + int y2 = int( _p.y() + width ); + + clampToViewport( x1, y1, x2, y2 ); + + int baseindex = 4 * x1 + ( m_width * 4 * y1 ); + + QColor color = m_fill->color(); + for( int i = 0; i < y2 - y1; i++ ) + { + for( int j = 0; j < x2 - x1; j++ ) + { + m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) ] = color.red(); + m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 1 ] = color.green(); + m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 2 ] = color.blue(); + m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 3 ] = 0xFF; + } + } +} + +void +VKoPainter::drawImage( const QImage &image, const QWMatrix &affine ) +{ + // set up world matrix + double affineresult[6]; + + affineresult[0] = affine.m11() * m_matrix.m11() * m_zoomFactor + affine.m12() * m_matrix.m21(); + affineresult[1] = (affine.m11() * m_matrix.m12() + affine.m12() * m_matrix.m22() ) * m_zoomFactor; + affineresult[2] = (affine.m21() * m_matrix.m11() + affine.m22() * m_matrix.m21() ) * m_zoomFactor; + affineresult[3] = affine.m22() * m_matrix.m22() * m_zoomFactor + affine.m21() * m_matrix.m12(); + affineresult[4] = m_matrix.dx() + affine.dx() * m_zoomFactor; + affineresult[5] = m_matrix.dy() - affine.dy() * m_zoomFactor; + + //art_affine_scale( affineresult, m_zoomFactor, m_zoomFactor); + /*kdDebug(38000) << "affineresult[0] : " << affineresult[0] << endl; + kdDebug(38000) << "affineresult[1] : " << affineresult[1] << endl; + kdDebug(38000) << "affineresult[2] : " << affineresult[2] << endl; + kdDebug(38000) << "affineresult[3] : " << affineresult[3] << endl; + kdDebug(38000) << "affineresult[4] : " << affineresult[4] << endl; + kdDebug(38000) << "affineresult[5] : " << affineresult[5] << endl; + kdDebug(38000) << "m_matrix.dx() : " << m_matrix.dx() << endl; + kdDebug(38000) << "affine.dx() : " << affine.dx() << endl; + kdDebug(38000) << "image.height() : " << image.height() << endl;*/ + art_rgba_affine( m_buffer, 0, 0, m_width, m_height, m_width * 4, + image.bits(), image.width(), image.height(), image.width() * 4, + affineresult, ART_FILTER_NEAREST, 0L ); +} + +void +VKoPainter::drawRect( const KoRect &r ) +{ + newPath(); + moveTo( r.topLeft() ); + lineTo( r.topRight() ); + lineTo( r.bottomRight() ); + lineTo( r.bottomLeft() ); + lineTo( r.topLeft() ); + fillPath(); + strokePath(); +} + +void +VKoPainter::drawRect( double x, double y, double w, double h ) +{ + drawRect( KoRect( x, y, w, h ) ); +} + diff --git a/karbon/render/vkopainter.h b/karbon/render/vkopainter.h new file mode 100644 index 00000000..48336092 --- /dev/null +++ b/karbon/render/vkopainter.h @@ -0,0 +1,124 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VKOPAINTER_H__ +#define __VKOPAINTER_H__ + +// kopainter/libart wrapper + +#include "vpainter.h" +#include <qwmatrix.h> +#include <qptrlist.h> +#include <koffice_export.h> +class QPainter; +struct _ArtVpath; +struct _ArtBpath; +struct _ArtSVP; +struct _ArtGradientStop; +class VGradient; +class VPattern; +class KoRect; + +class KARBONBASE_EXPORT VKoPainter : public VPainter +{ +public: + VKoPainter( QPaintDevice *target, unsigned int w = 0, unsigned int h = 0, bool = true ); + VKoPainter( unsigned char *buffer, unsigned int w = 0, unsigned int h = 0, bool = true ); + virtual ~VKoPainter(); + + virtual void resize( unsigned int w, unsigned int h ); + virtual void begin(); + virtual void end(); + virtual void blit( const KoRect & ); + void clear(); + virtual void clear( const QColor & ); + virtual void clear( const KoRect &, const QColor & ); + + // matrix manipulation + virtual void setWorldMatrix( const QWMatrix & ); + virtual const QWMatrix worldMatrix() { return m_matrix; } + virtual void setZoomFactor( double ); + virtual double zoomFactor() { return m_zoomFactor; } + + // drawing + virtual void moveTo( const KoPoint & ); + virtual void lineTo( const KoPoint & ); + virtual void curveTo( const KoPoint &, const KoPoint &, const KoPoint & ); + virtual void newPath(); + virtual void fillPath(); + virtual void setFillRule( VFillRule ); + virtual void strokePath(); + virtual void setClipPath(); + virtual void resetClipPath(); + + // helper + virtual void drawNode( const KoPoint& p, int width ); + virtual void drawRect( const KoRect & ); + virtual void drawRect( double, double, double, double ); + + // pen + brush + virtual void setPen( const VStroke & ); + virtual void setPen( const QColor & ); + virtual void setPen( Qt::PenStyle style ); + virtual void setBrush( const VFill & ); + virtual void setBrush( const QColor & ); + virtual void setBrush( Qt::BrushStyle style ); + + virtual void drawImage( const QImage &, const QWMatrix & ); + + // stack management + virtual void save(); + virtual void restore(); + + // + virtual void setRasterOp( Qt::RasterOp ); + + virtual QPaintDevice *device() { return m_target; } + unsigned char *buffer() { return m_buffer; } + +private: + void drawVPath( struct _ArtVpath * ); + void applyGradient( _ArtSVP *, bool ); + void applyPattern( _ArtSVP *, bool ); + _ArtGradientStop *buildStopArray( VGradient &gradient, int & ); + void clampToViewport( const _ArtSVP &, int &, int &, int &, int & ); + void clampToViewport( int &, int &, int &, int & ); + void ensureSpace( unsigned int ); + +private: + struct _ArtBpath *m_path; + unsigned int m_index; + unsigned int m_alloccount; + unsigned char *m_buffer; + QPaintDevice *m_target; + unsigned int m_width; + unsigned int m_height; + QWMatrix m_matrix; + VStroke *m_stroke; + VFill *m_fill; + VFillRule m_fillRule; + double m_zoomFactor; + QPtrList<_ArtSVP> m_clipPaths; + + bool m_bDrawNodes; + + GC gc; +}; + +#endif diff --git a/karbon/render/vpainter.h b/karbon/render/vpainter.h new file mode 100644 index 00000000..b638ddcc --- /dev/null +++ b/karbon/render/vpainter.h @@ -0,0 +1,102 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __VPAINTER_H__ +#define __VPAINTER_H__ + +// painter abstraction + +#include <qnamespace.h> +#include <KoRect.h> +#include <vfillrule.h> + +class QWMatrix; +class QPaintDevice; +class QColor; +class QPen; +class QBrush; +class QImage; + +class VStroke; +class VFill; + +class KoPoint; +class KoRect; + +class VPainter +{ +public: + VPainter( QPaintDevice *, unsigned int /*w*/ = 0, unsigned int /*h*/ = 0 ) {}; + virtual ~VPainter() {}; + + // + virtual void resize( unsigned int w, unsigned int h ) = 0; + virtual void begin() = 0; + virtual void end() = 0; + virtual void blit( const KoRect & ) = 0; + virtual void clear( const QColor & ) = 0; + virtual void clear( const KoRect &, const QColor & ) = 0; + + // matrix manipulation + virtual void setWorldMatrix( const QWMatrix & ) = 0; + virtual const QWMatrix worldMatrix() = 0; + virtual void setZoomFactor( double ) = 0; + virtual double zoomFactor() { return 1.0; } + + // drawing + virtual void moveTo( const KoPoint & ) = 0; + virtual void lineTo( const KoPoint & ) = 0; + virtual void curveTo( const KoPoint &, const KoPoint &, const KoPoint & ) = 0; + virtual void newPath() = 0; + virtual void strokePath() = 0; + virtual void fillPath() = 0; + virtual void setFillRule( VFillRule ) = 0; + virtual void setClipPath() = 0; + virtual void resetClipPath() = 0; + + // helper + virtual void drawNode( const KoPoint& , int ) {} + virtual void drawRect( const KoRect & ) {} + virtual void drawRect( double, double, double, double ) {} + + // pen + brush + virtual void setPen( const VStroke & ) = 0; + // compatibility, use VPen/VBrush later ? + virtual void setPen( const QColor & ) = 0; + virtual void setPen( Qt::PenStyle style ) = 0; + virtual void setBrush( const VFill & ) = 0; + virtual void setBrush( const QColor & ) = 0; + virtual void setBrush( Qt::BrushStyle style ) = 0; + + virtual void drawImage( const QImage &, const QWMatrix & ) {} + + // stack management + virtual void save() = 0; + virtual void restore() = 0; + + // we have to see how this fits in + virtual void setRasterOp( Qt::RasterOp ) = 0; + + // access to device + virtual QPaintDevice *device() = 0; +}; + +#endif diff --git a/karbon/render/vpainterfactory.cc b/karbon/render/vpainterfactory.cc new file mode 100644 index 00000000..a4d52c62 --- /dev/null +++ b/karbon/render/vpainterfactory.cc @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +// painter factory + +#include "vpainterfactory.h" +#include "vkopainter.h" +#include "vqpainter.h" + +VPainterFactory::VPainterFactory() +{ + m_painter = 0L; + m_editpainter = 0L; +} + +VPainterFactory::~VPainterFactory() +{ + delete m_painter; + delete m_editpainter; +} + +VPainter * +VPainterFactory::painter() +{ + return m_painter; +} + +void +VPainterFactory::setPainter( QPaintDevice *target, int w, int h ) +{ + if( m_painter ) + delete m_painter; + m_painter = new VKoPainter( target, w, h ); +} + +VPainter * +VPainterFactory::editpainter() +{ + return m_editpainter; +} + +void +VPainterFactory::setEditPainter( QPaintDevice *target, int w, int h ) +{ + if( m_editpainter ) + delete m_editpainter; + m_editpainter = new VQPainter( target, w, h ); +} + +void +VPainterFactory::setWireframePainter( QPaintDevice *target, int w, int h ) +{ + if( m_painter ) + delete m_painter; + m_painter = new VQPainter( target, w, h ); +} + diff --git a/karbon/render/vpainterfactory.h b/karbon/render/vpainterfactory.h new file mode 100644 index 00000000..df36819d --- /dev/null +++ b/karbon/render/vpainterfactory.h @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPAINTERDACTORY_H__ +#define __VPAINTERDACTORY_H__ + +// painter factory +#include <koffice_export.h> +class VPainter; +class QPaintDevice; + +class KARBONBASE_EXPORT VPainterFactory +{ +public: + VPainterFactory(); + ~VPainterFactory(); + + VPainter *painter(); + void setPainter( QPaintDevice *target, int w = 0, int h = 0 ); + + VPainter *editpainter(); + void setEditPainter( QPaintDevice *target, int w = 0, int h = 0 ); + + void setWireframePainter( QPaintDevice *target, int w = 0, int h = 0 ); + +private: + VPainter *m_painter; + VPainter *m_editpainter; +}; + +#endif diff --git a/karbon/render/vqpainter.cc b/karbon/render/vqpainter.cc new file mode 100644 index 00000000..31e5593e --- /dev/null +++ b/karbon/render/vqpainter.cc @@ -0,0 +1,284 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +// qpainter wrapper + +#include "vqpainter.h" +#include "vstroke.h" +#include "vcolor.h" +#include "vfill.h" + +#include <qpainter.h> +#include <qpaintdevice.h> +#include <qpen.h> + +#include <KoPoint.h> +#include <kdebug.h> + +VQPainter::VQPainter( QPaintDevice *target, unsigned int w, unsigned int h ) : VPainter( target, w, h ), m_painter( 0L ), m_target( target ), m_width( w ), m_height( h ) +{ + m_zoomFactor = 1; + m_index = 0; + m_painter = new QPainter( target ); +} + +VQPainter::~VQPainter() +{ + delete m_painter; +} + +void +VQPainter::resize( unsigned int w, unsigned int h ) +{ + m_width = w; + m_height = h; +} + +void +VQPainter::blit( const KoRect & ) +{ + end(); +} + +void +VQPainter::clear( const QColor &c ) +{ + m_painter->setBackgroundColor( c ); + m_painter->eraseRect( 0, 0, m_width, m_height ); +} + +void +VQPainter::begin() +{ + if( !m_painter->isActive() ) + { + m_painter->begin( m_target ); + m_painter->eraseRect( 0, 0, m_width, m_height ); + } +} + +void +VQPainter::end() +{ + m_painter->end(); +} + +const QWMatrix +VQPainter::worldMatrix() +{ + return m_painter->worldMatrix(); +} + +void +VQPainter::setWorldMatrix( const QWMatrix& mat ) +{ + m_painter->setWorldMatrix( mat ); +} + +void +VQPainter::setZoomFactor( double zoomFactor ) +{ + m_zoomFactor = zoomFactor; + /*QWMatrix mat; + mat.scale( zoomFactor, zoomFactor ); + m_painter->setWorldMatrix( mat );*/ +} + +void +VQPainter::moveTo( const KoPoint &p ) +{ + //m_index = 0; + if( m_pa.size() <= m_index ) + m_pa.resize( m_index + 10 ); + + m_pa.setPoint( m_index, static_cast<int>(p.x() * m_zoomFactor), static_cast<int>(p.y() * m_zoomFactor) ); + + m_index++; +} + +void +VQPainter::lineTo( const KoPoint &p ) +{ + if( m_pa.size() <= m_index ) + m_pa.resize( m_index + 10 ); + + m_pa.setPoint( m_index, static_cast<int>(p.x() * m_zoomFactor), static_cast<int>(p.y() * m_zoomFactor) ); + + m_index++; +} + +void +VQPainter::curveTo( const KoPoint &p1, const KoPoint &p2, const KoPoint &p3 ) +{ + // calculate cubic bezier using a temp QPointArray + QPointArray pa( 4 ); + pa.setPoint( 0, m_pa.point( m_index - 1 ).x(), m_pa.point( m_index - 1 ).y() ); + pa.setPoint( 1, static_cast<int>(p1.x() * m_zoomFactor), static_cast<int>(p1.y() * m_zoomFactor) ); + pa.setPoint( 2, static_cast<int>(p2.x() * m_zoomFactor), static_cast<int>(p2.y() * m_zoomFactor) ); + pa.setPoint( 3, static_cast<int>(p3.x() * m_zoomFactor), static_cast<int>(p3.y() * m_zoomFactor) ); + + QPointArray pa2( pa.cubicBezier() ); + + m_pa.resize( m_index + pa2.size() ); + m_pa.putPoints( m_index, pa2.size(), pa2 ); + + m_index += pa2.size(); +} + +void +VQPainter::newPath() +{ + m_index = 0; +} + +void +VQPainter::fillPath() +{ + // we probably dont need filling for qpainter + //m_index = 0; + m_painter->drawPolygon( m_pa, FALSE, 0, m_index ); +} + +void +VQPainter::strokePath() +{ + m_painter->drawPolyline( m_pa, 0, m_index ); + m_index = 0; +} + +void +VQPainter::setPen( const VStroke &stroke ) +{ + QPen pen; + + // color + linewidth + pen.setColor( stroke.color() ); + pen.setWidth( static_cast<int>(stroke.lineWidth()) ); + + // caps + if( stroke.lineCap() == VStroke::capButt ) + pen.setCapStyle( Qt::FlatCap ); + else if( stroke.lineCap() == VStroke::capRound ) + pen.setCapStyle( Qt::RoundCap ); + else if( stroke.lineCap() == VStroke::capSquare ) + pen.setCapStyle( Qt::SquareCap ); + + m_painter->setPen( pen ); +} + +void +VQPainter::setBrush( const VFill &fill ) +{ + switch( fill.type() ) + { + case VFill::none: + m_painter->setBrush( Qt::NoBrush ); + break; + case VFill::solid: + m_painter->setBrush( QBrush( fill.color(), Qt::SolidPattern ) ); + break; + case VFill::grad: + // gradients are nor supported by qpainter + m_painter->setBrush( Qt::NoBrush ); + break; + case VFill::patt: + // pixmap brushes not supported for printing + m_painter->setBrush( QBrush( fill.color(), fill.pattern().pixmap() ) ); + break; + default: + break; + } +} + +void +VQPainter::setPen( const QColor &c ) +{ + m_painter->setPen( c ); +} + +void +VQPainter::setPen( Qt::PenStyle style ) +{ + m_painter->setPen( style ); +} + +void +VQPainter::setBrush( const QColor &c ) +{ + m_painter->setBrush( c ); +} + +void +VQPainter::setBrush( Qt::BrushStyle style ) +{ + m_painter->setBrush( style ); +} + +void +VQPainter::save() +{ + m_painter->save(); +} + +void +VQPainter::restore() +{ + m_painter->restore(); +} + +void +VQPainter::setRasterOp( Qt::RasterOp r ) +{ + m_painter->setRasterOp( r ); +} + +void +VQPainter::drawNode( const KoPoint &p, int width ) +{ + m_painter->drawRect( QRect( int( p.x() * m_zoomFactor ) - width, int( p.y() * m_zoomFactor ) - width, + 2 * width + 1, 2 * width + 1 ) ); +} + +void +VQPainter::drawRect( const KoRect &rect ) +{ + m_painter->drawRect( QRect( int( rect.x() ), int( rect.y() ), int( rect.width() ), int( rect.height() ) ) ); +} + +void +VQPainter::drawImage( const QImage &image, const QWMatrix &affine ) +{ + QWMatrix matrix = m_painter->worldMatrix(); + + double m11 = affine.m11() * matrix.m11() * m_zoomFactor + affine.m12() * matrix.m21(); + double m12 = (affine.m11() * matrix.m12() + affine.m12() * matrix.m22() ) * m_zoomFactor; + double m21 = (affine.m21() * matrix.m11() + affine.m22() * matrix.m21() ) * m_zoomFactor; + double m22 = affine.m22() * matrix.m22() * m_zoomFactor + affine.m21() * matrix.m12(); + double dx = matrix.dx() + affine.dx() * m_zoomFactor; + double dy = matrix.dy() - affine.dy() * m_zoomFactor; + + QWMatrix world( m11, m12, m21, m22, dx, dy ); + + m_painter->setWorldMatrix( world ); + + m_painter->drawImage( QPoint( 0, 0 ), image ); + // restore old world matrix + m_painter->setWorldMatrix( matrix ); +} diff --git a/karbon/render/vqpainter.h b/karbon/render/vqpainter.h new file mode 100644 index 00000000..7f4f501b --- /dev/null +++ b/karbon/render/vqpainter.h @@ -0,0 +1,95 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VQPAINTER_H__ +#define __VQPAINTER_H__ + +// qpainter wrapper + +#include "vpainter.h" +#include "qpointarray.h" + +class QPainter; + +class VQPainter : public VPainter +{ +public: + VQPainter( QPaintDevice *target, unsigned int w = 0, unsigned int h = 0 ); + virtual ~VQPainter(); + + // + virtual void resize( unsigned int w, unsigned int h ); + virtual void begin(); + virtual void end(); + virtual void blit( const KoRect & ); + virtual void clear( const QColor & ); + virtual void clear( const KoRect &, const QColor & ) {} + + // matrix manipulation + virtual void setWorldMatrix( const QWMatrix & ); + virtual const QWMatrix worldMatrix(); + virtual void setZoomFactor( double ); + virtual double zoomFactor() { return m_zoomFactor; } + + // drawing + virtual void moveTo( const KoPoint & ); + virtual void lineTo( const KoPoint & ); + virtual void curveTo( const KoPoint &, const KoPoint &, const KoPoint & ); + virtual void newPath(); + virtual void strokePath(); + virtual void fillPath(); + virtual void setFillRule( VFillRule ) {} + virtual void setClipPath() {} + virtual void resetClipPath() {} + + // pen + brush + virtual void setPen( const VStroke & ); + virtual void setPen( const QColor & ); + virtual void setPen( Qt::PenStyle style ); + virtual void setBrush( const VFill & ); + virtual void setBrush( const QColor & ); + virtual void setBrush( Qt::BrushStyle style ); + + virtual void drawImage( const QImage &, const QWMatrix & ); + + // stack management + virtual void save(); + virtual void restore(); + + // helper + virtual void drawNode( const KoPoint& , int ); + virtual void drawRect( const KoRect & ); + + // + virtual void setRasterOp( Qt::RasterOp ); + + virtual QPaintDevice *device() { return m_target; } + +private: + double m_zoomFactor; + unsigned int m_index; + QPointArray m_pa; + QPainter *m_painter; + QPaintDevice *m_target; + unsigned int m_width; + unsigned int m_height; +}; + +#endif diff --git a/karbon/render/xrgbrender/Makefile.am b/karbon/render/xrgbrender/Makefile.am new file mode 100644 index 00000000..dcfe376a --- /dev/null +++ b/karbon/render/xrgbrender/Makefile.am @@ -0,0 +1,5 @@ +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libkarbonxrgbrender.la + +libkarbonxrgbrender_la_SOURCES = gdk-pixbuf-xlib.c gdk-pixbuf-xlib-render.c gdk-pixbuf-xlib-drawable.c gdk-pixbuf-xlibrgb.c diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlib-drawable.c b/karbon/render/xrgbrender/gdk-pixbuf-xlib-drawable.c new file mode 100644 index 00000000..7e955610 --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlib-drawable.c @@ -0,0 +1,1137 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* GdkPixbuf library - convert X drawable information to RGB + * + * Copyright (C) 1999 Michael Zucchi + * + * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au> + * Cody Russell <bratsche@dfw.net> + * Federico Mena-Quintero <federico@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* Ported to Xlib by John Harper <john@dcs.warwick.ac.uk> */ + + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include "gdk-pixbuf-xlib-private.h" +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#if (KSVG_BYTE_ORDER == KSVG_LITTLE_ENDIAN) +#define LITTLE +#endif +#define d(x) + + + +static unsigned int mask_table[] = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, + 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, + 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, + 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + + +/* color handling */ + +typedef struct xlib_colormap_struct xlib_colormap; +struct xlib_colormap_struct { + int size; + XColor *colors; + Visual *visual; + Colormap colormap; +}; + + +/* from gdkvisual.c */ +static void +visual_decompose_mask (unsigned long mask, + int *shift, + int *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) { + (*prec)++; + mask >>= 1; + } +} + +static int x_error; + +static int +handle_x_error (Display *dpy, XErrorEvent *ev) +{ + x_error = 1; + return 0; +} + +static int +drawable_is_pixmap (Drawable d) +{ + /* copied from Imlib */ + + XErrorHandler errh; + XWindowAttributes wa; + int is_pixmap; + + errh = XSetErrorHandler (handle_x_error); + x_error = 0; + XGetWindowAttributes (gdk_pixbuf_dpy, d, &wa); + XSync (gdk_pixbuf_dpy, False); + is_pixmap = x_error; + XSetErrorHandler (errh); + + return is_pixmap; +} + + + +/* + convert 1 bits-pixel data + no alpha +*/ +static void +rgb1 (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + unsigned char *s; + register unsigned char data; + unsigned char *o; + unsigned char *srow = image->data, *orow = pixels; + + d (printf ("1 bits/pixel\n")); + + /* convert upto 8 pixels/time */ + /* its probably not worth trying to make this run very fast, who uses + 1 bit displays anymore? */ + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + + for (xx = 0; xx < width; xx ++) { + data = srow[xx >> 3] >> (7 - (xx & 7)) & 1; + *o++ = colormap->colors[data].red; + *o++ = colormap->colors[data].green; + *o++ = colormap->colors[data].blue; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 1 bits/pixel data + with alpha +*/ +static void +rgb1a (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + unsigned char *s; + register unsigned char data; + unsigned char *o; + unsigned char *srow = image->data, *orow = pixels; + unsigned int remap[2]; + + d (printf ("1 bits/pixel\n")); + + /* convert upto 8 pixels/time */ + /* its probably not worth trying to make this run very fast, who uses + 1 bit displays anymore? */ + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (xx = 0; xx < 2; xx++) { +#ifdef LITTLE + remap[xx] = 0xff000000 + | colormap->colors[xx].blue << 16 + | colormap->colors[xx].green << 8 + | colormap->colors[xx].red; +#else + remap[xx] = 0xff + | colormap->colors[xx].red << 24 + | colormap->colors[xx].green << 16 + | colormap->colors[xx].blue << 8; +#endif + } + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + + for (xx = 0; xx < width; xx ++) { + data = srow[xx >> 3] >> (7 - (xx & 7)) & 1; + *o++ = remap[data]; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 8 bits/pixel data + no alpha +*/ +static void +rgb8 (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + unsigned int mask; + register unsigned int data; + unsigned char *srow = image->data, *orow = pixels; + register unsigned char *s; + register unsigned char *o; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + d (printf ("8 bit, no alpha output\n")); + + mask = mask_table[image->depth]; + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) { + data = *s++ & mask; + *o++ = colormap->colors[data].red; + *o++ = colormap->colors[data].green; + *o++ = colormap->colors[data].blue; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 8 bits/pixel data + with alpha +*/ +static void +rgb8a (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + unsigned int mask; + register unsigned int data; + unsigned int remap[256]; + register unsigned char *s; /* read 2 pixels at once */ + register unsigned int *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + d (printf ("8 bit, with alpha output\n")); + + mask = mask_table[image->depth]; + + for (xx = 0; xx < colormap->size; xx++) { +#ifdef LITTLE + remap[xx] = 0xff000000 + | colormap->colors[xx].blue << 16 + | colormap->colors[xx].green << 8 + | colormap->colors[xx].red; +#else + remap[xx] = 0xff + | colormap->colors[xx].red << 24 + | colormap->colors[xx].green << 16 + | colormap->colors[xx].blue << 8; +#endif + } + + for (yy = 0; yy < height; yy++) { + s = srow; + o = (unsigned int *) orow; + for (xx = 0; xx < width; xx ++) { + data = *s++ & mask; + *o++ = remap[data]; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 16 bits/pixel data + no alpha + data in lsb format +*/ +static void +rgb565lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned int *s; /* read 2 pixels at once */ +#else + register unsigned char *s; /* read 2 pixels at once */ +#endif + register unsigned short *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned int *) srow; +#else + s = srow; +#endif + o = (unsigned short *) orow; + for (xx = 1; xx < width; xx += 2) { + register unsigned int data; +#ifdef LITTLE + data = *s++; + *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13 + | (data & 0x7e0) << 5 | (data & 0x600) >> 1; + *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2 + | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21; + *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25 + | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10; +#else + /* swap endianness first */ + data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + s += 4; + *o++ = (data & 0xf800) | (data & 0xe000) >> 5 + | (data & 0x7e0) >> 3 | (data & 0x600) >> 9; + *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6 + | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29; + *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17 + | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18; +#endif + } + /* check for last remaining pixel */ + if (width & 1) { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); +#else + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#endif + ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7); + ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3); + ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7); + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 16 bits/pixel data + no alpha + data in msb format +*/ +static void +rgb565msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned char *s; /* need to swap data order */ +#else + register unsigned int *s; /* read 2 pixels at once */ +#endif + register unsigned short *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = srow; +#else + s = (unsigned int *) srow; +#endif + o = (unsigned short *) orow; + for (xx = 1; xx < width; xx += 2) { + register unsigned int data; +#ifdef LITTLE + /* swap endianness first */ + data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + s += 4; + *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13 + | (data & 0x7e0) << 5 | (data & 0x600) >> 1; + *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2 + | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21; + *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25 + | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10; +#else + data = *s++; + *o++ = (data & 0xf800) | (data & 0xe000) >> 5 + | (data & 0x7e0) >> 3 | (data & 0x600) >> 9; + *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6 + | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29; + *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17 + | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18; +#endif + } + /* check for last remaining pixel */ + if (width & 1) { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#else + data = *((short *) s); +#endif + ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7); + ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3); + ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7); + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 16 bits/pixel data + with alpha + data in lsb format +*/ +static void +rgb565alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned short *s; /* read 1 pixels at once */ +#else + register unsigned char *s; +#endif + register unsigned int *o; + + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned short *) srow; +#else + s = (unsigned char *) srow; +#endif + o = (unsigned int *) orow; + for (xx = 0; xx < width; xx ++) { + register unsigned int data; + /* rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */ + /* little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */ +#ifdef LITTLE + data = *s++; + *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13 + | (data & 0x7e0) << 5 | (data & 0x600) >> 1 + | (data & 0x1f) << 19 | (data & 0x1c) << 14 + | 0xff000000; +#else + /* swap endianness first */ + data = s[0] | s[1] << 8; + s += 2; + *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11 + | (data & 0x7e0) << 13 | (data & 0x600) << 7 + | (data & 0x1f) << 11 | (data & 0x1c) << 6 + | 0xff; +#endif + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 16 bits/pixel data + with alpha + data in msb format +*/ +static void +rgb565amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned char *s; +#else + register unsigned short *s; /* read 1 pixels at once */ +#endif + register unsigned int *o; + + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { + s = srow; + o = (unsigned int *) orow; + for (xx = 0; xx < width; xx ++) { + register unsigned int data; + /* rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */ + /* little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */ +#ifdef LITTLE + /* swap endianness first */ + data = s[0] | s[1] << 8; + s += 2; + *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13 + | (data & 0x7e0) << 5 | (data & 0x600) >> 1 + | (data & 0x1f) << 19 | (data & 0x1c) << 14 + | 0xff000000; +#else + data = *s++; + *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11 + | (data & 0x7e0) << 13 | (data & 0x600) << 7 + | (data & 0x1f) << 11 | (data & 0x1c) << 6 + | 0xff; +#endif + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 15 bits/pixel data + no alpha + data in lsb format +*/ +static void +rgb555lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned int *s; /* read 2 pixels at once */ +#else + register unsigned char *s; /* read 2 pixels at once */ +#endif + register unsigned short *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned int *) srow; +#else + s = srow; +#endif + o = (unsigned short *) orow; + for (xx = 1; xx < width; xx += 2) { + register unsigned int data; +#ifdef LITTLE + data = *s++; + *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12 + | (data & 0x3e0) << 6 | (data & 0x380) << 1; + *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2 + | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20; + *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23 + | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10; +#else + /* swap endianness first */ + data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + s += 4; + *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4 + | (data & 0x3e0) >> 2 | (data & 0x380) >> 7; + *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6 + | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28; + *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15 + | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18; +#endif + } + /* check for last remaining pixel */ + if (width & 1) { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); +#else + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#endif + ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12; + ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7; + ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 15 bits/pixel data + no alpha + data in msb format +*/ +static void +rgb555msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned char *s; /* read 2 pixels at once */ +#else + register unsigned int *s; /* read 2 pixels at once */ +#endif + register unsigned short *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { + s = srow; + o = (unsigned short *) orow; + for (xx = 1; xx < width; xx += 2) { + register unsigned int data; +#ifdef LITTLE + /* swap endianness first */ + data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + s += 4; + *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12 + | (data & 0x3e0) << 6 | (data & 0x380) << 1; + *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2 + | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20; + *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23 + | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10; +#else + data = *s++; + *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4 + | (data & 0x3e0) >> 2 | (data & 0x380) >> 7; + *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6 + | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28; + *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15 + | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18; +#endif + } + /* check for last remaining pixel */ + if (width & 1) { + register unsigned short data; +#ifdef LITTLE + data = *((short *) s); + data = ((data >> 8) & 0xff) | ((data & 0xff) << 8); +#else + data = *((short *) s); +#endif + ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12; + ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7; + ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2; + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 15 bits/pixel data + with alpha + data in lsb format +*/ +static void +rgb555alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned short *s; /* read 1 pixels at once */ +#else + register unsigned char *s; +#endif + register unsigned int *o; + + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned short *) srow; +#else + s = srow; +#endif + o = (unsigned int *) orow; + for (xx = 0; xx < width; xx++) { + register unsigned int data; + /* rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */ + /* little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */ +#ifdef LITTLE + data = *s++; + *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12 + | (data & 0x3e0) << 6 | (data & 0x380) << 1 + | (data & 0x1f) << 19 | (data & 0x1c) << 14 + | 0xff000000; +#else + /* swap endianness first */ + data = s[0] | s[1] << 8; + s += 2; + *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12 + | (data & 0x3e0) << 14 | (data & 0x380) << 9 + | (data & 0x1f) << 11 | (data & 0x1c) << 6 + | 0xff; +#endif + } + srow += bpl; + orow += rowstride; + } +} + +/* + convert 15 bits/pixel data + with alpha + data in msb format +*/ +static void +rgb555amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + +#ifdef LITTLE + register unsigned short *s; /* read 1 pixels at once */ +#else + register unsigned char *s; +#endif + register unsigned int *o; + + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned short *) srow; +#else + s = srow; +#endif + o = (unsigned int *) orow; + for (xx = 0; xx < width; xx++) { + register unsigned int data; + /* rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */ + /* little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */ +#ifdef LITTLE + /* swap endianness first */ + data = s[0] | s[1] << 8; + s += 2; + *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12 + | (data & 0x3e0) << 6 | (data & 0x380) << 1 + | (data & 0x1f) << 19 | (data & 0x1c) << 14 + | 0xff000000; +#else + data = *s++; + *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12 + | (data & 0x3e0) << 14 | (data & 0x380) << 9 + | (data & 0x1f) << 11 | (data & 0x1c) << 6 + | 0xff; +#endif + } + srow += bpl; + orow += rowstride; + } +} + + +static void +rgb888alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + + unsigned char *s; /* for byte order swapping */ + unsigned char *o; + unsigned char *srow = image->data, *orow = pixels; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + d (printf ("32 bits/pixel with alpha\n")); + + /* lsb data */ + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) { + *o++ = s[2]; + *o++ = s[1]; + *o++ = s[0]; + *o++ = 0xff; + s += 4; + } + srow += bpl; + orow += rowstride; + } +} + +static void +rgb888lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + + unsigned char *srow = image->data, *orow = pixels; + unsigned char *o, *s; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + d (printf ("32 bit, lsb, no alpha\n")); + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) { + *o++ = s[2]; + *o++ = s[1]; + *o++ = s[0]; + s += 4; + } + srow += bpl; + orow += rowstride; + } +} + +static void +rgb888amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + + unsigned char *srow = image->data, *orow = pixels; +#ifdef LITTLE + unsigned int *o; + unsigned int *s; +#else + unsigned char *s; /* for byte order swapping */ + unsigned char *o; +#endif + + d (printf ("32 bit, msb, with alpha\n")); + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + /* msb data */ + for (yy = 0; yy < height; yy++) { +#ifdef LITTLE + s = (unsigned int *) srow; + o = (unsigned int *) orow; +#else + s = srow; + o = orow; +#endif + for (xx = 0; xx < width; xx++) { +#ifdef LITTLE + *o++ = s[1]; + *o++ = s[2]; + *o++ = s[3]; + *o++ = 0xff; + s += 4; +#else + *o++ = (*s << 8) | 0xff; /* untested */ + s++; +#endif + } + srow += bpl; + orow += rowstride; + } +} + +static void +rgb888msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap) +{ + int xx, yy; + int width, height; + int bpl; + + unsigned char *srow = image->data, *orow = pixels; + unsigned char *s; + unsigned char *o; + + d (printf ("32 bit, msb, no alpha\n")); + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) { + *o++ = s[1]; + *o++ = s[2]; + *o++ = s[3]; + s += 4; + } + srow += bpl; + orow += rowstride; + } +} + +/* + This should work correctly with any display/any endianness, but will probably + run quite slow +*/ +static void +convert_real_slow (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *cmap, int alpha) +{ + int xx, yy; + int width, height; + int bpl; + unsigned char *srow = image->data, *orow = pixels; + unsigned char *s; + unsigned char *o; + unsigned int pixel; + Visual *v; + unsigned char component; + int i; + int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec; + + width = image->width; + height = image->height; + bpl = image->bytes_per_line; + v = cmap->visual; + + visual_decompose_mask (v->red_mask, &red_shift, &red_prec); + visual_decompose_mask (v->green_mask, &green_shift, &green_prec); + visual_decompose_mask (v->blue_mask, &blue_shift, &blue_prec); + + d(printf("rgb mask/shift/prec = %x:%x:%x %d:%d:%d %d:%d:%d\n", + v->red_mask, v->green_mask, v->blue_mask, + red_shift, green_shift, blue_shift, + red_prec, green_prec, blue_prec)); + + for (yy = 0; yy < height; yy++) { + s = srow; + o = orow; + for (xx = 0; xx < width; xx++) { + pixel = XGetPixel (image, xx, yy); + switch (v->class) { + /* I assume this is right for static & greyscale's too? */ + case StaticGray: + case GrayScale: + case StaticColor: + case PseudoColor: + *o++ = cmap->colors[pixel].red; + *o++ = cmap->colors[pixel].green; + *o++ = cmap->colors[pixel].blue; + break; + case TrueColor: + /* This is odd because it must sometimes shift left (otherwise + I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic + should work for all bit sizes/shifts/etc. */ + component = 0; + for (i = 24; i < 32; i += red_prec) + component |= ((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> i; + *o++ = component; + component = 0; + for (i = 24; i < 32; i += green_prec) + component |= ((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> i; + *o++ = component; + component = 0; + for (i = 24; i < 32; i += blue_prec) + component |= ((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> i; + *o++ = component; + break; + case DirectColor: + *o++ = cmap->colors[((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> 24].red; + *o++ = cmap->colors[((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> 24].green; + *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> 24].blue; + break; + } + if (alpha) + *o++ = 0xff; + } + srow += bpl; + orow += rowstride; + } +} + +typedef void (* cfunc) (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *cmap); + +static cfunc convert_map[] = { + rgb1,rgb1,rgb1a,rgb1a, + rgb8,rgb8,rgb8a,rgb8a, + rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb, + rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb, + rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb +}; + +/* + perform actual conversion + + If we can, try and use the optimised code versions, but as a default + fallback, and always for direct colour, use the generic/slow but complete + conversion function. +*/ +static void +rgbconvert (XImage *image, unsigned char *pixels, int rowstride, int alpha, xlib_colormap *cmap) +{ + int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1; + int bank=5; /* default fallback converter */ + Visual *v = cmap->visual; + + d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask)); + d(printf("image depth = %d, bpp = %d\n", image->depth, image->bits_per_pixel)); + + switch (v->class) { + /* I assume this is right for static & greyscale's too? */ + case StaticGray: + case GrayScale: + case StaticColor: + case PseudoColor: + switch (image->bits_per_pixel) { + case 1: + bank = 0; + break; + case 8: + bank = 1; + break; + } + break; + case TrueColor: + switch (image->depth) { + case 15: + if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f + && image->bits_per_pixel == 16) + bank = 2; + break; + case 16: + if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f + && image->bits_per_pixel == 16) + bank = 3; + break; + case 24: + case 32: + if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff + && image->bits_per_pixel == 32) + bank = 4; + break; + } + break; + case DirectColor: + /* always use the slow version */ + break; + } + + d(printf("converting using conversion function in bank %d\n", bank)); + + if (bank==5) { + convert_real_slow(image, pixels, rowstride, cmap, alpha); + } else { + index |= bank << 2; + (* convert_map[index]) (image, pixels, rowstride, cmap); + } +} + +static int +xlib_window_is_viewable (Window w) +{ + XWindowAttributes wa; + + while (w != 0) { + Window parent, root, *children; + int nchildren; + + XGetWindowAttributes (gdk_pixbuf_dpy, w, &wa); + if (wa.map_state != IsViewable) + return 0; + + if (!XQueryTree (gdk_pixbuf_dpy, w, &root, + &parent, &children, &nchildren)) + return 0; + + if (nchildren > 0) + XFree (children); + + if (parent == root) + return 1; + + w = parent; + } + + return 0; +} + +static int +xlib_window_get_origin (Window w, int *x, int *y) +{ + Window child; + return XTranslateCoordinates (gdk_pixbuf_dpy, w, + RootWindow (gdk_pixbuf_dpy, + gdk_pixbuf_screen), + 0, 0, x, y, &child); +} diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlib-private.h b/karbon/render/xrgbrender/gdk-pixbuf-xlib-private.h new file mode 100644 index 00000000..0198ec00 --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlib-private.h @@ -0,0 +1,39 @@ +/* GdkPixbuf library - Xlib header file + * + * Authors: John Harper <john@dcs.warwick.ac.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDK_PIXBUF_XLIB_PRIVATE_H +#define GDK_PIXBUF_XLIB_PRIVATE_H + +#include <config.h> +#include "gdk-pixbuf-xlib.h" +#include <X11/Xlib.h> + +extern Display *gdk_pixbuf_dpy; +extern int gdk_pixbuf_screen; + +#define KSVG_LITTLE_ENDIAN 1 +#define KSVG_BIG_ENDIAN 2 + +#if X_BYTE_ORDER == X_BIG_ENDIAN +#define KSVG_BYTE_ORDER KSVG_BIG_ENDIAN +#else +#define KSVG_BYTE_ORDER KSVG_LITTLE_ENDIAN +#endif +#endif diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlib-render.c b/karbon/render/xrgbrender/gdk-pixbuf-xlib-render.c new file mode 100644 index 00000000..f2439138 --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlib-render.c @@ -0,0 +1,380 @@ +/* GdkPixbuf library - Rendering functions + * + * Copyright (C) 1999 The Free Software Foundation + * + * Author: Federico Mena-Quintero <federico@gimp.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* Trivially ported to Xlib(RGB) by John Harper. */ + +#include <config.h> +/* #include "gdk-pixbuf-private.h" */ +#include "gdk-pixbuf-xlib-private.h" + + +/* +** + * gdk_pixbuf_xlib_render_threshold_alpha: + * @pixbuf: A pixbuf. + * @bitmap: Bitmap where the bilevel mask will be painted to. + * @src_x: Source X coordinate. + * @src_y: source Y coordinate. + * @dest_x: Destination X coordinate. + * @dest_y: Destination Y coordinate. + * @width: Width of region to threshold. + * @height: Height of region to threshold. + * @alpha_threshold: Opacity values below this will be painted as zero; all + * other values will be painted as one. + * + * Takes the opacity values in a rectangular portion of a pixbuf and thresholds + * them to produce a bi-level alpha mask that can be used as a clipping mask for + * a drawable. + * +void +gdk_pixbuf_xlib_render_threshold_alpha (GdkPixbuf *pixbuf, Pixmap bitmap, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int alpha_threshold) +{ + GC gc; + XColor color; + int x, y; + guchar *p; + int start, start_status; + int status; + XGCValues gcv; + + g_return_if_fail (pixbuf != NULL); + g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); + g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->bits_per_sample == 8); + + g_return_if_fail (bitmap != 0); + g_return_if_fail (width >= 0 && height >= 0); + g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width); + g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height); + + g_return_if_fail (alpha_threshold >= 0 && alpha_threshold <= 255); + + if (width == 0 || height == 0) + return; + + gc = XCreateGC (gdk_pixbuf_dpy, bitmap, 0, &gcv); + + if (!pixbuf->has_alpha) { + color.pixel = (alpha_threshold == 255) ? 0 : 1; + XSetForeground (gdk_pixbuf_dpy, gc, color.pixel); + XFillRectangle (gdk_pixbuf_dpy, bitmap, gc, + dest_x, dest_y, width, height); + XFreeGC (gdk_pixbuf_dpy, gc); + return; + } + + color.pixel = 0; + XSetForeground (gdk_pixbuf_dpy, gc, color.pixel); + XFillRectangle (gdk_pixbuf_dpy, bitmap, gc, + dest_x, dest_y, width, height); + + color.pixel = 1; + XSetForeground (gdk_pixbuf_dpy, gc, color.pixel); + + for (y = 0; y < height; y++) { + p = (pixbuf->pixels + (y + src_y) * pixbuf->rowstride + src_x * pixbuf->n_channels + + pixbuf->n_channels - 1); + + start = 0; + start_status = *p < alpha_threshold; + + for (x = 0; x < width; x++) { + status = *p < alpha_threshold; + + if (status != start_status) { + if (!start_status) + XDrawLine (gdk_pixbuf_dpy, bitmap, gc, + start + dest_x, y + dest_y, + x - 1 + dest_x, y + dest_y); + + start = x; + start_status = status; + } + + p += pixbuf->n_channels; + } + + if (!start_status) + XDrawLine (gdk_pixbuf_dpy, bitmap, gc, + start + dest_x, y + dest_y, + x - 1 + dest_x, y + dest_y); + } + + XFreeGC (gdk_pixbuf_dpy, gc); +} + + +static guchar * +remove_alpha (GdkPixbuf *pixbuf, int x, int y, int width, int height, int *rowstride) +{ + guchar *buf; + int xx, yy; + guchar *src, *dest; + + g_assert (pixbuf->n_channels == 4); + g_assert (pixbuf->has_alpha); + g_assert (width > 0 && height > 0); + g_assert (x >= 0 && x + width <= pixbuf->width); + g_assert (y >= 0 && y + height <= pixbuf->height); + + *rowstride = 4 * ((width * 3 + 3) / 4); + + buf = g_new (guchar, *rowstride * height); + + for (yy = 0; yy < height; yy++) { + src = pixbuf->pixels + pixbuf->rowstride * (yy + y) + x * pixbuf->n_channels; + dest = buf + *rowstride * yy; + + for (xx = 0; xx < width; xx++) { + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + src++; + } + } + + return buf; +} + + * gdk_pixbuf_xlib_render_to_drawable: + * @pixbuf: A pixbuf. + * @drawable: Destination drawable. + * @gc: GC used for rendering. + * @src_x: Source X coordinate within pixbuf. + * @src_y: Source Y coordinate within pixbuf. + * @dest_x: Destination X coordinate within drawable. + * @dest_y: Destination Y coordinate within drawable. + * @width: Width of region to render, in pixels. + * @height: Height of region to render, in pixels. + * @dither: Dithering mode for XlibRGB. + * @x_dither: X offset for dither. + * @y_dither: Y offset for dither. + * + * Renders a rectangular portion of a pixbuf to a drawable while using the + * specified GC. This is done using XlibRGB, so the specified drawable must + * have the XlibRGB visual and colormap. Note that this function will ignore + * the opacity information for images with an alpha channel; the GC must already + * have the clipping mask set if you want transparent regions to show through. + * + * For an explanation of dither offsets, see the XlibRGB documentation. In + * brief, the dither offset is important when re-rendering partial regions of an + * image to a rendered version of the full image, or for when the offsets to a + * base position change, as in scrolling. The dither matrix has to be shifted + * for consistent visual results. If you do not have any of these cases, the + * dither offsets can be both zero. +void +gdk_pixbuf_xlib_render_to_drawable (GdkPixbuf *pixbuf, + Drawable drawable, GC gc, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + XlibRgbDither dither, + int x_dither, int y_dither) +{ + guchar *buf; + int rowstride; + + g_return_if_fail (pixbuf != NULL); + g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); + g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->bits_per_sample == 8); + + g_return_if_fail (drawable != 0); + g_return_if_fail (gc != 0); + + g_return_if_fail (width >= 0 && height >= 0); + g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width); + g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height); + + if (width == 0 || height == 0) + return; + + if (pixbuf->has_alpha) + buf = remove_alpha (pixbuf, src_x, src_y, width, height, &rowstride); + else { + buf = pixbuf->pixels + src_y * pixbuf->rowstride + src_x * 3; + rowstride = pixbuf->rowstride; + } + + xlib_draw_rgb_image_dithalign (drawable, gc, + dest_x, dest_y, + width, height, + dither, + buf, rowstride, + x_dither, y_dither); + + if (pixbuf->has_alpha) + g_free (buf); +} + + + + * gdk_pixbuf_xlib_render_to_drawable_alpha: + * @pixbuf: A pixbuf. + * @drawable: Destination drawable. + * @src_x: Source X coordinate within pixbuf. + * @src_y: Source Y coordinates within pixbuf. + * @dest_x: Destination X coordinate within drawable. + * @dest_y: Destination Y coordinate within drawable. + * @width: Width of region to render, in pixels. + * @height: Height of region to render, in pixels. + * @alpha_mode: If the image does not have opacity information, this is ignored. + * Otherwise, specifies how to handle transparency when rendering. + * @alpha_threshold: If the image does have opacity information and @alpha_mode + * is GDK_PIXBUF_ALPHA_BILEVEL, specifies the threshold value for opacity + * values. + * @dither: Dithering mode for XlibRGB. + * @x_dither: X offset for dither. + * @y_dither: Y offset for dither. + * + * Renders a rectangular portion of a pixbuf to a drawable. This is done using + * XlibRGB, so the specified drawable must have the XlibRGB visual and colormap. + * + * When used with #GDK_PIXBUF_ALPHA_BILEVEL, this function has to create a bitmap + * out of the thresholded alpha channel of the image and, it has to set this + * bitmap as the clipping mask for the GC used for drawing. This can be a + * significant performance penalty depending on the size and the complexity of + * the alpha channel of the image. If performance is crucial, consider handling + * the alpha channel yourself (possibly by caching it in your application) and + * using gdk_pixbuf_xlib_render_to_drawable() or GdkRGB directly instead. +void +gdk_pixbuf_xlib_render_to_drawable_alpha (GdkPixbuf *pixbuf, Drawable drawable, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + GdkPixbufAlphaMode alpha_mode, + int alpha_threshold, + XlibRgbDither dither, + int x_dither, int y_dither) +{ + Pixmap bitmap = 0; + GC gc; + XGCValues gcv; + + g_return_if_fail (pixbuf != NULL); + g_return_if_fail (pixbuf->colorspace == GDK_COLORSPACE_RGB); + g_return_if_fail (pixbuf->n_channels == 3 || pixbuf->n_channels == 4); + g_return_if_fail (pixbuf->bits_per_sample == 8); + + g_return_if_fail (drawable != 0); + g_return_if_fail (width >= 0 && height >= 0); + g_return_if_fail (src_x >= 0 && src_x + width <= pixbuf->width); + g_return_if_fail (src_y >= 0 && src_y + height <= pixbuf->height); + + if (width == 0 || height == 0) + return; + + gc = XCreateGC (gdk_pixbuf_dpy, drawable, 0, &gcv); + + if (pixbuf->has_alpha) { + + bitmap = XCreatePixmap (gdk_pixbuf_dpy, + RootWindow (gdk_pixbuf_dpy, + gdk_pixbuf_screen), + width, height, 1); + gdk_pixbuf_xlib_render_threshold_alpha (pixbuf, bitmap, + src_x, src_y, + 0, 0, + width, height, + alpha_threshold); + + XSetClipMask (gdk_pixbuf_dpy, gc, bitmap); + XSetClipOrigin (gdk_pixbuf_dpy, gc, dest_x, dest_y); + } + + gdk_pixbuf_xlib_render_to_drawable (pixbuf, drawable, gc, + src_x, src_y, + dest_x, dest_y, + width, height, + dither, + x_dither, y_dither); + + if (bitmap) + XFreePixmap (gdk_pixbuf_dpy, bitmap); + + XFreeGC (gdk_pixbuf_dpy, gc); +} + + * @pixbuf: A pixbuf. + * @pixmap_return: Return value for the created pixmap. + * @mask_return: Return value for the created mask. + * @alpha_threshold: Threshold value for opacity values. + * + * Creates a pixmap and a mask bitmap which are returned in the @pixmap_return + * and @mask_return arguments, respectively, and renders a pixbuf and its + * corresponding tresholded alpha mask to them. This is merely a convenience + * function; applications that need to render pixbufs with dither offsets or to + * given drawables should use gdk_pixbuf_xlib_render_to_drawable_alpha() or + * gdk_pixbuf_xlib_render_to_drawable(), and + * gdk_pixbuf_xlib_render_threshold_alpha(). + * + * If the pixbuf does not have an alpha channel, then *@mask_return will be set + * to None. +void +gdk_pixbuf_xlib_render_pixmap_and_mask (GdkPixbuf *pixbuf, + Pixmap *pixmap_return, + Pixmap *mask_return, + int alpha_threshold) +{ + g_return_if_fail (pixbuf != NULL); + + if (pixmap_return) { + GC gc; + XGCValues gcv; + + *pixmap_return = XCreatePixmap (gdk_pixbuf_dpy, + RootWindow (gdk_pixbuf_dpy, + gdk_pixbuf_screen), + pixbuf->width, + pixbuf->height, + xlib_rgb_get_depth ()); + gc = XCreateGC (gdk_pixbuf_dpy, *pixmap_return, 0, &gcv); + gdk_pixbuf_xlib_render_to_drawable (pixbuf, *pixmap_return, gc, + 0, 0, 0, 0, + pixbuf->width, + pixbuf->height, + XLIB_RGB_DITHER_NORMAL, + 0, 0); + XFreeGC (gdk_pixbuf_dpy, gc); + } + + if (mask_return) { + if (pixbuf->has_alpha) { + *mask_return = XCreatePixmap (gdk_pixbuf_dpy, + RootWindow (gdk_pixbuf_dpy, + gdk_pixbuf_screen), + pixbuf->width, + pixbuf->height, 1); + gdk_pixbuf_xlib_render_threshold_alpha (pixbuf, + *mask_return, + 0, 0, 0, 0, + pixbuf->width, + pixbuf->height, + alpha_threshold); + } else + *mask_return = 0; + } +}*/ diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlib.c b/karbon/render/xrgbrender/gdk-pixbuf-xlib.c new file mode 100644 index 00000000..ff41ccdf --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlib.c @@ -0,0 +1,63 @@ +/* GdkPixbuf library - Initialization functions + * + * Author: John Harper <john@dcs.warwick.ac.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <config.h> +#include <X11/Xlib.h> +/*#include <gdk-pixbuf/gdk-pixbuf-private.h>*/ +#include "gdk-pixbuf-xlib-private.h" + +Display *gdk_pixbuf_dpy = NULL; +int gdk_pixbuf_screen = -1; + +/** + * gdk_pixbuf_xlib_init: + * @display: X display to use. + * @screen_num: Screen number. + * + * Initializes the gdk-pixbuf Xlib machinery by calling xlib_rgb_init(). This + * function should be called near the beginning of your program, or before using + * any of the gdk-pixbuf-xlib functions. + **/ +void +gdk_pixbuf_xlib_init (Display *display, int screen_num) +{ + xlib_rgb_init (display, ScreenOfDisplay (display, screen_num)); + gdk_pixbuf_dpy = display; + gdk_pixbuf_screen = screen_num; +} + +/** + * gdk_pixbuf_xlib_init_with_depth: + * @display: X display to use. + * @screen_num: Screen number. + * @prefDepth: Preferred depth for XlibRGB. + * + * Similar to gdk_pixbuf_xlib_init(), but also lets you specify the preferred + * depth for XlibRGB if you do not want it to use the default depth it picks. + **/ +void +gdk_pixbuf_xlib_init_with_depth (Display *display, + int screen_num, int prefDepth) +{ + xlib_rgb_init_with_depth (display, ScreenOfDisplay (display, screen_num), + prefDepth); + gdk_pixbuf_dpy = display; + gdk_pixbuf_screen = screen_num; +} diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlib.h b/karbon/render/xrgbrender/gdk-pixbuf-xlib.h new file mode 100644 index 00000000..2b31ed7e --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlib.h @@ -0,0 +1,80 @@ +/* GdkPixbuf library - Xlib header file + * + * Authors: John Harper <john@dcs.warwick.ac.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GDK_PIXBUF_XLIB_H +#define GDK_PIXBUF_XLIB_H + +/* #include <gdk-pixbuf/gdk-pixbuf.h> */ +/* #include <gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h> */ +#include <X11/Xlib.h> + + + +/* init */ + +void gdk_pixbuf_xlib_init (Display *display, int screen_num); + +void gdk_pixbuf_xlib_init_with_depth (Display *display, int screen_num, + int prefDepth); + + + +/* render */ +/* +void gdk_pixbuf_xlib_render_threshold_alpha (GdkPixbuf *pixbuf, Pixmap bitmap, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int alpha_threshold); + +void gdk_pixbuf_xlib_render_to_drawable (GdkPixbuf *pixbuf, + Drawable drawable, GC gc, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + XlibRgbDither dither, + int x_dither, int y_dither); + + +void gdk_pixbuf_xlib_render_to_drawable_alpha (GdkPixbuf *pixbuf, + Drawable drawable, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + GdkPixbufAlphaMode alpha_mode, + int alpha_threshold, + XlibRgbDither dither, + int x_dither, int y_dither); + +void gdk_pixbuf_xlib_render_pixmap_and_mask (GdkPixbuf *pixbuf, + Pixmap *pixmap_return, + Pixmap *mask_return, + int alpha_threshold); + + + +GdkPixbuf *gdk_pixbuf_xlib_get_from_drawable (GdkPixbuf *dest, + Drawable src, + Colormap cmap, Visual *visual, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height); +*/ +#endif /* GDK_PIXBUF_XLIB_H */ diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.c b/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.c new file mode 100644 index 00000000..171db33d --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.c @@ -0,0 +1,3724 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "MPL"); you may not use this file except in + * compliance with the MPL. You may obtain a copy of the MPL at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the MPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL + * for the specific language governing rights and limitations under the + * MPL. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Library General Public License (the "LGPL"), in + * which case the provisions of the LGPL are applicable instead of + * those above. If you wish to allow use of your version of this file + * only under the terms of the LGPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the LGPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the LGPL. + */ + +/* + * This code is derived from GdkRgb. + * For more information on GdkRgb, see http://www.levien.com/gdkrgb/ + * Raph Levien <raph@acm.org> + */ + +/* Ported by Christopher Blizzard to Xlib. With permission from the + * original authors and the copyright holders of this file, the + * contents of this file are also redistributable under the terms of + * the Mozilla Public license. For information about the Mozilla + * Public License, please see the license information at + * http://www.mozilla.org/MPL/ */ + +/* This code is copyright the following authors: + * Raph Levien <raph@acm.org> + * Manish Singh <manish@gtk.org> + * Tim Janik <timj@gtk.org> + * Peter Mattis <petm@xcf.berkeley.edu> + * Spencer Kimball <spencer@xcf.berkeley.edu> + * Josh MacDonald <jmacd@xcf.berkeley.edu> + * Christopher Blizzard <blizzard@redhat.com> + * Owen Taylor <otaylor@redhat.com> + * Shawn T. Amundson <amundson@gtk.org> +*/ + +#include <math.h> + +#if HAVE_CONFIG_H +# include <config.h> +# if STDC_HEADERS +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +#endif + +#define ENABLE_GRAYSCALE + +/* include this before so that we can get endian definitions if + they are there... */ + +#include "gdk-pixbuf-xlibrgb.h" +#include "gdk-pixbuf-xlib-private.h" + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +typedef enum { + LSB_FIRST, + MSB_FIRST +} ByteOrder; + + +typedef struct _XlibRgbInfo XlibRgbInfo; + +typedef void (*XlibRgbConvFunc) (XImage *image, + int ax, int ay, + int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap); + +/* Some of these fields should go, as they're not being used at all. + Globals should generally migrate into here - it's very likely that + we'll want to run more than one GdkRgbInfo context at the same time + (i.e. some but not all windows have privately installed + colormaps). */ + +struct _XlibRgbInfo +{ + Display *display; + Screen *screen; + int screen_num; + XVisualInfo *x_visual_info; + Colormap cmap; + XColor *cmap_colors; + Visual *default_visualid; + Colormap default_colormap; + + unsigned long *color_pixels; + unsigned long *gray_pixels; + unsigned long *reserved_pixels; + + unsigned long red_shift; + unsigned long red_prec; + unsigned long blue_shift; + unsigned long blue_prec; + unsigned long green_shift; + unsigned long green_prec; + + unsigned int nred_shades; + unsigned int ngreen_shades; + unsigned int nblue_shades; + unsigned int ngray_shades; + unsigned int nreserved; + + unsigned int bpp; + unsigned int cmap_alloced; + double gamma_val; + + /* Generally, the stage buffer is used to convert 32bit RGB, gray, + and indexed images into 24 bit packed RGB. */ + unsigned char *stage_buf; + + XlibRgbCmap *gray_cmap; + + Bool dith_default; + + Bool bitmap; /* set true if in 1 bit per pixel mode */ + GC own_gc; + + /* Convert functions */ + XlibRgbConvFunc conv; + XlibRgbConvFunc conv_d; + + XlibRgbConvFunc conv_32; + XlibRgbConvFunc conv_32_d; + + XlibRgbConvFunc conv_gray; + XlibRgbConvFunc conv_gray_d; + + XlibRgbConvFunc conv_indexed; + XlibRgbConvFunc conv_indexed_d; +}; + +static Bool xlib_rgb_install_cmap = FALSE; +static int xlib_rgb_min_colors = 5 * 5 * 5; +static Bool xlib_rgb_verbose = FALSE; + +#define IMAGE_WIDTH 256 +#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3) +#define IMAGE_HEIGHT 64 +#define N_IMAGES 6 + +static XlibRgbInfo *image_info = NULL; +static XImage *static_image[N_IMAGES]; +static int static_image_idx; + +static unsigned char *colorcube; +static unsigned char *colorcube_d; + +static unsigned long +xlib_get_prec_from_mask(unsigned long val) +{ + unsigned long retval = 0; + unsigned int cur_bit = 0; + /* walk through the number, incrementing the value if + the bit in question is set. */ + while (cur_bit < (sizeof(unsigned long) * 8)) { + if ((val >> cur_bit) & 0x1) { + retval++; + } + cur_bit++; + } + return retval; +} + +static unsigned long +xlib_get_shift_from_mask(unsigned long val) +{ + unsigned long cur_bit = 0; + /* walk through the number, looking for the first 1 */ + while (cur_bit < (sizeof(unsigned long) * 8)) { + if ((val >> cur_bit) & 0x1) { + return cur_bit; + } + cur_bit++; + } + return cur_bit; +} + + +static int +xlib_rgb_cmap_fail (const char *msg, Colormap cmap, unsigned long *pixels) +{ + unsigned long free_pixels[256]; + int n_free; + int i; + +#ifdef VERBOSE + printf ("%s", msg); +#endif + n_free = 0; + for (i = 0; i < 256; i++) + if (pixels[i] < 256) + free_pixels[n_free++] = pixels[i]; + + if (n_free) + XFreeColors(image_info->display, + cmap, + free_pixels, + n_free, + 0); + return 0; +} + +static void +xlib_rgb_make_colorcube (unsigned long *pixels, int nr, int ng, int nb) +{ + unsigned char rt[16], gt[16], bt[16]; + int i; + + colorcube = malloc(sizeof(unsigned char) * 4096); + memset(colorcube, 0, (sizeof(unsigned char) * 4096)); + for (i = 0; i < 16; i++) + { + rt[i] = ng * nb * ((i * 17 * (nr - 1) + 128) >> 8); + gt[i] = nb * ((i * 17 * (ng - 1) + 128) >> 8); + bt[i] = ((i * 17 * (nb - 1) + 128) >> 8); + } + + for (i = 0; i < 4096; i++) + { + colorcube[i] = pixels[rt[i >> 8] + gt[(i >> 4) & 0x0f] + bt[i & 0x0f]]; +#ifdef VERBOSE + printf ("%03x %02x %x %x %x\n", i, colorcube[i], rt[i >> 8], gt[(i >> 4) & 0x0f], bt[i & 0x0f]); +#endif + } +} + +/* this is the colorcube suitable for dithering */ +static void +xlib_rgb_make_colorcube_d (unsigned long *pixels, int nr, int ng, int nb) +{ + int r, g, b; + int i; + + colorcube_d = malloc(sizeof(unsigned char) * 512); + memset(colorcube_d, 0, (sizeof(unsigned char) * 512)); + for (i = 0; i < 512; i++) + { + r = MIN (nr - 1, i >> 6); + g = MIN (ng - 1, (i >> 3) & 7); + b = MIN (nb - 1, i & 7); + colorcube_d[i] = pixels[(r * ng + g) * nb + b]; + } +} + +/* Try installing a color cube of the specified size. + Make the colorcube and return TRUE on success */ +static int +xlib_rgb_try_colormap (int nr, int ng, int nb) +{ + int r, g, b; + int ri, gi, bi; + int r0, g0, b0; + Colormap cmap; + XVisualInfo *visual; + XColor *colors = NULL; + XColor color; + unsigned long pixels[256]; + unsigned long junk[256]; + int i; + int d2; + unsigned int colors_needed; + int idx; + int best[256]; + + if (nr * ng * nb < xlib_rgb_min_colors) + return FALSE; + + if (image_info->cmap_alloced) { + cmap = image_info->cmap; + visual = image_info->x_visual_info; + } + else { + cmap = image_info->default_colormap; + visual = image_info->x_visual_info; + } + colors_needed = nr * ng * nb; + for (i = 0; i < 256; i++) + { + best[i] = 192; + pixels[i] = 256; + } + +#ifndef GAMMA + if (!xlib_rgb_install_cmap) { + /* go out and get the colors for this colormap. */ + colors = malloc(sizeof(XColor) * visual->colormap_size); + for (i=0; i < visual->colormap_size; i++){ + colors[i].pixel = i; + } + XQueryColors (image_info->display, + cmap, + colors, visual->colormap_size); + /* find color cube colors that are already present */ + for (i = 0; i < MIN (256, visual->colormap_size); i++) + { + r = colors[i].red >> 8; + g = colors[i].green >> 8; + b = colors[i].blue >> 8; + ri = (r * (nr - 1) + 128) >> 8; + gi = (g * (ng - 1) + 128) >> 8; + bi = (b * (nb - 1) + 128) >> 8; + r0 = ri * 255 / (nr - 1); + g0 = gi * 255 / (ng - 1); + b0 = bi * 255 / (nb - 1); + idx = ((ri * nr) + gi) * nb + bi; + d2 = (r - r0) * (r - r0) + (g - g0) * (g - g0) + (b - b0) * (b - b0); + if (d2 < best[idx]) { + if (pixels[idx] < 256) + XFreeColors(image_info->display, + cmap, + pixels + idx, + 1, 0); + else + colors_needed--; + color.pixel = colors[i].pixel; + color.red = colors[i].red; + color.green = colors[i].green; + color.blue = colors[i].blue; + color.flags = 0; + if (!XAllocColor(image_info->display, cmap, &color)) + return xlib_rgb_cmap_fail ("error allocating system color\n", + cmap, pixels); + pixels[idx] = color.pixel; /* which is almost certainly i */ + best[idx] = d2; + } + } + } + +#endif + + if (colors_needed) + { + if (!XAllocColorCells(image_info->display, cmap, 0, NULL, 0, junk, colors_needed)) + { + char tmp_str[80]; + + sprintf (tmp_str, + "%d %d %d colormap failed (in XAllocColorCells)\n", + nr, ng, nb); + return xlib_rgb_cmap_fail (tmp_str, cmap, pixels); + } + XFreeColors(image_info->display, cmap, junk, (int)colors_needed, 0); + } + + for (r = 0, i = 0; r < nr; r++) + for (g = 0; g < ng; g++) + for (b = 0; b < nb; b++, i++) + { + if (pixels[i] == 256) + { + color.red = r * 65535 / (nr - 1); + color.green = g * 65535 / (ng - 1); + color.blue = b * 65535 / (nb - 1); + +#ifdef GAMMA + color.red = 65535 * pow (color.red / 65535.0, 0.5); + color.green = 65535 * pow (color.green / 65535.0, 0.5); + color.blue = 65535 * pow (color.blue / 65535.0, 0.5); +#endif + + /* This should be a raw XAllocColor call */ + if (!XAllocColor(image_info->display, cmap, &color)) + { + char tmp_str[80]; + + sprintf (tmp_str, "%d %d %d colormap failed\n", + nr, ng, nb); + return xlib_rgb_cmap_fail (tmp_str, + cmap, pixels); + } + pixels[i] = color.pixel; + } +#ifdef VERBOSE + printf ("%d: %lx\n", i, pixels[i]); +#endif + } + + image_info->nred_shades = nr; + image_info->ngreen_shades = ng; + image_info->nblue_shades = nb; + xlib_rgb_make_colorcube (pixels, nr, ng, nb); + xlib_rgb_make_colorcube_d (pixels, nr, ng, nb); + if (colors) + free(colors); + return TRUE; +} + +/* Return TRUE on success. */ +static Bool +xlib_rgb_do_colormaps (void) +{ + static const int sizes[][3] = { + /* { 6, 7, 6 }, */ + { 6, 6, 6 }, + { 6, 6, 5 }, + { 6, 6, 4 }, + { 5, 5, 5 }, + { 5, 5, 4 }, + { 4, 4, 4 }, + { 4, 4, 3 }, + { 3, 3, 3 }, + { 2, 2, 2 } + }; + static const int n_sizes = sizeof(sizes) / (3 * sizeof(int)); + int i; + + for (i = 0; i < n_sizes; i++) + if (xlib_rgb_try_colormap (sizes[i][0], sizes[i][1], sizes[i][2])) + return TRUE; + return FALSE; +} + +/* Make a 2 x 2 x 2 colorcube */ +static void +xlib_rgb_colorcube_222 (void) +{ + int i; + XColor color; + Colormap cmap; + + if (image_info->cmap_alloced) + cmap = image_info->cmap; + else + cmap = image_info->default_colormap; + + colorcube_d = malloc(sizeof(unsigned char) * 512); + + for (i = 0; i < 8; i++) + { + color.red = ((i & 4) >> 2) * 65535; + color.green = ((i & 2) >> 1) * 65535; + color.blue = (i & 1) * 65535; + XAllocColor (image_info->display, cmap, &color); + colorcube_d[((i & 4) << 4) | ((i & 2) << 2) | (i & 1)] = color.pixel; + } +} + +/** + * xlib_rgb_set_verbose: + * @verbose: %True to be verbose + * + * Enables/disables debug spew. + **/ +void +xlib_rgb_set_verbose (Bool verbose) +{ + xlib_rgb_verbose = verbose; +} + +/** + * xlib_rgb_set_install: + * @install: %True to install a colormap + * + * Sets whether we install an RGB colormap. + **/ +void +xlib_rgb_set_install (Bool install) +{ + xlib_rgb_install_cmap = install; +} + +/** + * xlib_rgb_set_min_colors: + * @min_colors: minimum colors to use + * + * Sets the minimum number of colors in the color cube. + **/ +void +xlib_rgb_set_min_colors (int min_colors) +{ + xlib_rgb_min_colors = min_colors; +} + +/* Return a "score" based on the following criteria (in hex): + + x000 is the quality - 1 is 1bpp, 2 is 4bpp, + 4 is 8bpp, + 7 is 15bpp truecolor, 8 is 16bpp truecolor, + 9 is 24bpp truecolor. + 0x00 is the speed - 1 is the normal case, + 2 means faster than normal + 00x0 gets a point for being the system visual + 000x gets a point for being pseudocolor + + A caveat: in the 8bpp modes, being the system visual seems to be + quite important. Thus, all of the 8bpp modes should be ranked at + the same speed. +*/ + +static unsigned int +xlib_rgb_score_visual (XVisualInfo *visual) +{ + unsigned int quality, speed, pseudo, sys; + static const char* visual_names[] = + { + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", + }; + + + quality = 0; + speed = 1; + sys = 0; + if (visual->class == TrueColor || + visual->class == DirectColor) + { + if (visual->depth == 24) + { + quality = 9; + /* Should test for MSB visual here, and set speed if so. */ + } + else if (visual->depth == 16) + quality = 8; + else if (visual->depth == 15) + quality = 7; + else if (visual->depth == 8) + quality = 4; + } + else if (visual->class == PseudoColor || + visual->class == StaticColor) + { + if (visual->depth == 8) + quality = 4; + else if (visual->depth == 4) + quality = 2; + else if (visual->depth == 1) + quality = 1; + } + else if (visual->class == StaticGray +#ifdef ENABLE_GRAYSCALE + || visual->class == GrayScale +#endif + ) + { + if (visual->depth == 8) + quality = 4; + else if (visual->depth == 4) + quality = 2; + else if (visual->depth == 1) + quality = 1; + } + + if (quality == 0) + return 0; + + sys = (visual->visualid == image_info->default_visualid->visualid); + + pseudo = (visual->class == PseudoColor || visual->class == TrueColor); + + if (xlib_rgb_verbose) + printf ("Visual 0x%x, type = %s, depth = %d, %ld:%ld:%ld%s; score=%x\n", + (int)visual->visualid, + visual_names[visual->class], + visual->depth, + visual->red_mask, + visual->green_mask, + visual->blue_mask, + sys ? " (system)" : "", + (quality << 12) | (speed << 8) | (sys << 4) | pseudo); + + return (quality << 12) | (speed << 8) | (sys << 4) | pseudo; +} + +static void +xlib_rgb_choose_visual (void) +{ + XVisualInfo *visuals; + XVisualInfo *visual; + XVisualInfo *best_visual; + XVisualInfo *final_visual; + XVisualInfo template; + int num_visuals; + unsigned int score, best_score; + int cur_visual = 1; + int i; + + template.screen = image_info->screen_num; + visuals = XGetVisualInfo(image_info->display, VisualScreenMask, + &template, &num_visuals); + + best_visual = visuals; + best_score = xlib_rgb_score_visual (best_visual); + + for (i = cur_visual; i < num_visuals; i++) + { + visual = &visuals[i]; + score = xlib_rgb_score_visual (visual); + if (score > best_score) + { + best_score = score; + best_visual = visual; + } + } + /* make a copy of the visual so that we can free + the allocated visual list above. */ + final_visual = malloc(sizeof(XVisualInfo)); + memcpy(final_visual, best_visual, sizeof(XVisualInfo)); + image_info->x_visual_info = final_visual; + XFree(visuals); + /* set up the shift and the precision for the red, green and blue. + this only applies to cool visuals like true color and direct color. */ + if (image_info->x_visual_info->class == TrueColor || + image_info->x_visual_info->class == DirectColor) { + image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask); + image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask); + image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask); + image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask); + image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask); + image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask); + } +} + +static void +xlib_rgb_choose_visual_for_xprint (int aDepth) +{ + XVisualInfo *visuals; + XVisualInfo *visual; + XVisualInfo *best_visual; + XVisualInfo *final_visual; + XVisualInfo template; + int num_visuals; + int cur_visual = 1; + int i; + + XWindowAttributes win_att; + Status ret_stat; + Visual *root_visual; + + ret_stat = XGetWindowAttributes(image_info->display, + RootWindow(image_info->display, image_info->screen_num), + &win_att); + root_visual = win_att.visual; + template.screen = image_info->screen_num; + visuals = XGetVisualInfo(image_info->display, VisualScreenMask, + &template, &num_visuals); + + best_visual = visuals; + if (best_visual->visual != root_visual) { + for (i = cur_visual; i < num_visuals; i++) { + visual = &visuals[i]; + if (visual->visual == root_visual) { + best_visual = visual; + break; + } + } + } + /* make a copy of the visual so that we can free + the allocated visual list above. */ + final_visual = malloc(sizeof(XVisualInfo)); + memcpy(final_visual, best_visual, sizeof(XVisualInfo)); + image_info->x_visual_info = final_visual; + XFree(visuals); + /* set up the shift and the precision for the red, green and blue. + this only applies to cool visuals like true color and direct color. */ + if (image_info->x_visual_info->class == TrueColor || + image_info->x_visual_info->class == DirectColor) { + image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask); + image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask); + image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask); + image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask); + image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask); + image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask); + } +} + +static void xlib_rgb_select_conv (XImage *image, ByteOrder byte_order); + +static void +xlib_rgb_set_gray_cmap (Colormap cmap) +{ + int i; + XColor color; + int status; + unsigned long pixels[256]; + int r, g, b, gray; + + for (i = 0; i < 256; i++) + { + color.pixel = i; + color.red = i * 257; + color.green = i * 257; + color.blue = i * 257; + status = XAllocColor(image_info->display, cmap, &color); + pixels[i] = color.pixel; +#ifdef VERBOSE + printf ("allocating pixel %d, %x %x %x, result %d\n", + color.pixel, color.red, color.green, color.blue, status); +#endif + } + + /* Now, we make fake colorcubes - we ultimately just use the pseudocolor + methods. */ + + colorcube = malloc(sizeof(unsigned char) * 4096); + + for (i = 0; i < 4096; i++) + { + r = (i >> 4) & 0xf0; + r = r | r >> 4; + g = i & 0xf0; + g = g | g >> 4; + b = (i << 4 & 0xf0); + b = b | b >> 4; + gray = (g + ((r + b) >> 1)) >> 1; + colorcube[i] = pixels[gray]; + } +} + +/** + * xlib_rgb_init: + * @display: X Display to use. + * @screen: Screen to use. + * + * Initializes the XlibRGB machinery with the default depth. If you use this + * function XlibRGB will automatically pick the best visual available on your + * display. This function or xlib_rgb_init_with_depth() must be called before + * using any of the other functions in XlibRGB. + **/ +void +xlib_rgb_init (Display *display, Screen *screen) +{ + int prefDepth = -1; /* let the function do the visual scoring */ + xlib_rgb_init_with_depth(display, screen, prefDepth); +} + +/** + * xlib_rgb_init_with_depth: + * @display: X display to use. + * @screen: Screen to use. + * @prefDepth: Visual depth to use for color substitution tables. This must + * be one of the supported visual depths in the specified @display. + * + * Initializes the XlibRGB machinery with a particular depth you specify, + * instead of automatically picking the best depth in the display. This + * function or xlib_rgb_init() must be called before using any of the other + * functions in XlibRGB. + **/ +void +xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth) +{ + int i; + static const int byte_order[1] = { 1 }; + + static int initialized = 0; + + if (initialized) + { + return; + } + + initialized = 1; + +#if KSVG_BYTE_ORDER == KSVG_BIG_ENDIAN + if (((char *)byte_order)[0] == 1) { + printf ("xlib_rgb_init: compiled for big endian, but this is a little endian machine.\n\n"); + exit(1); + } +#else + if (((char *)byte_order)[0] != 1) { + printf ("xlib_rgb_init: compiled for little endian, but this is a big endian machine.\n\n"); + exit(1); + } +#endif + + if (image_info == NULL) + { + image_info = malloc(sizeof(XlibRgbInfo)); + memset(image_info, 0, sizeof(XlibRgbInfo)); + + image_info->display = display; + image_info->screen = screen; + image_info->screen_num = XScreenNumberOfScreen(screen); + image_info->x_visual_info = NULL; + image_info->cmap = 0; + image_info->default_visualid = DefaultVisual(display, image_info->screen_num); + image_info->default_colormap = DefaultColormap(display, image_info->screen_num); + + image_info->color_pixels = NULL; + image_info->gray_pixels = NULL; + image_info->reserved_pixels = NULL; + + image_info->nred_shades = 6; + image_info->ngreen_shades = 6; + image_info->nblue_shades = 4; + image_info->ngray_shades = 24; + image_info->nreserved = 0; + + image_info->bpp = 0; + image_info->cmap_alloced = FALSE; + image_info->gamma_val = 1.0; + + image_info->stage_buf = NULL; + + image_info->own_gc = 0; + + image_info->red_shift = 0; + image_info->red_prec = 0; + image_info->green_shift = 0; + image_info->green_prec = 0; + image_info->blue_shift = 0; + image_info->blue_prec = 0; + + if (prefDepth != -1) + xlib_rgb_choose_visual_for_xprint (prefDepth); + else + xlib_rgb_choose_visual (); + + if ((image_info->x_visual_info->class == PseudoColor || + image_info->x_visual_info->class == StaticColor) && + image_info->x_visual_info->depth < 8 && + image_info->x_visual_info->depth >= 3) + { + image_info->cmap = image_info->default_colormap; + xlib_rgb_colorcube_222 (); + } + else if (image_info->x_visual_info->class == PseudoColor) + { + if (xlib_rgb_install_cmap || + image_info->x_visual_info->visualid != image_info->default_visualid->visualid) + { + image_info->cmap = XCreateColormap(image_info->display, + RootWindow(image_info->display, image_info->screen_num), + image_info->x_visual_info->visual, + AllocNone); + image_info->cmap_alloced = TRUE; + } + if (!xlib_rgb_do_colormaps ()) + { + image_info->cmap = XCreateColormap(image_info->display, + RootWindow(image_info->display, image_info->screen_num), + image_info->x_visual_info->visual, + AllocNone); + image_info->cmap_alloced = TRUE; + xlib_rgb_do_colormaps (); + } + if (xlib_rgb_verbose) + printf ("color cube: %d x %d x %d\n", + image_info->nred_shades, + image_info->ngreen_shades, + image_info->nblue_shades); + + if (!image_info->cmap_alloced) + image_info->cmap = image_info->default_colormap; + } +#ifdef ENABLE_GRAYSCALE + else if (image_info->x_visual_info->class == GrayScale) + { + image_info->cmap = XCreateColormap(image_info->display, + RootWindow(image_info->display, image_info->screen_num), + image_info->x_visual_info->visual, + AllocNone); + xlib_rgb_set_gray_cmap (image_info->cmap); + image_info->cmap_alloced = TRUE; + } +#endif + else + { + /* Always install colormap in direct color. */ + if (image_info->x_visual_info->class != DirectColor && + image_info->x_visual_info->visualid == image_info->default_visualid->visualid) + image_info->cmap = image_info->default_colormap; + else + { + image_info->cmap = XCreateColormap(image_info->display, + RootWindow(image_info->display, image_info->screen_num), + image_info->x_visual_info->visual, + AllocNone); + image_info->cmap_alloced = TRUE; + } + } + + image_info->bitmap = (image_info->x_visual_info->depth == 1); + + for (i = 0; i < N_IMAGES; i++) { + if (image_info->bitmap) { + /* Use malloc() instead of g_malloc since X will free() this mem */ + static_image[i] = XCreateImage(image_info->display, + image_info->x_visual_info->visual, + 1, + XYBitmap, + 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, + 8, + 0); + static_image[i]->data = malloc(IMAGE_WIDTH * IMAGE_HEIGHT >> 3); + static_image[i]->bitmap_bit_order = MSBFirst; + static_image[i]->byte_order = MSBFirst; + } + else { + static_image[i] = XCreateImage(image_info->display, + image_info->x_visual_info->visual, + (unsigned int)image_info->x_visual_info->depth, + ZPixmap, + 0, 0, + IMAGE_WIDTH, + IMAGE_HEIGHT, + 32, 0); + /* remove this when we are using shared memory.. */ + static_image[i]->data = malloc((size_t)IMAGE_WIDTH * IMAGE_HEIGHT * image_info->x_visual_info->depth); + static_image[i]->bitmap_bit_order = MSBFirst; + static_image[i]->byte_order = MSBFirst; + } + } + /* ok, so apparently, image_info->bpp is actually + BYTES per pixel. What fun! */ + switch (static_image[0]->bits_per_pixel) { + case 1: + case 8: + image_info->bpp = 1; + break; + case 16: + image_info->bpp = 2; + break; + case 24: + image_info->bpp = 3; + break; + case 32: + image_info->bpp = 4; + break; + } + xlib_rgb_select_conv (static_image[0], MSB_FIRST); + } +} + +/** + * xlib_rgb_xpixel_from_rgb: + * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB. + * + * Converts an RGB triplet into the closest color that XlibRGB visual can + * handle. + * + * Return value: X pixel value that corresponds to the closest color in the + * XlibRGB visual and colormap. + **/ +unsigned long +xlib_rgb_xpixel_from_rgb (unsigned int rgb) +{ + unsigned long pixel = 0; + + if (image_info->bitmap) + { + return ((rgb & 0xff0000) >> 16) + + ((rgb & 0xff00) >> 7) + + (rgb & 0xff) > 510; + } + else if (image_info->x_visual_info->class == PseudoColor) + pixel = colorcube[((rgb & 0xf00000) >> 12) | + ((rgb & 0xf000) >> 8) | + ((rgb & 0xf0) >> 4)]; + else if (image_info->x_visual_info->depth < 8 && + image_info->x_visual_info->class == StaticColor) + { + pixel = colorcube_d[((rgb & 0x800000) >> 17) | + ((rgb & 0x8000) >> 12) | + ((rgb & 0x80) >> 7)]; + } + else if (image_info->x_visual_info->class == TrueColor || + image_info->x_visual_info->class == DirectColor) + { +#ifdef VERBOSE + printf ("shift, prec: r %d %d g %d %d b %d %d\n", + image_info->red_shift, + image_info->red_prec, + image_info->green_shift, + image_info->green_prec, + image_info->blue_shift, + image_info->blue_prec); +#endif + + pixel = (((((rgb & 0xff0000) >> 16) >> + (8 - image_info->red_prec)) << + image_info->red_shift) + + ((((rgb & 0xff00) >> 8) >> + (8 - image_info->green_prec)) << + image_info->green_shift) + + (((rgb & 0xff) >> + (8 - image_info->blue_prec)) << + image_info->blue_shift)); + } + else if (image_info->x_visual_info->class == StaticGray || + image_info->x_visual_info->class == GrayScale) + { + int gray = ((rgb & 0xff0000) >> 16) + + ((rgb & 0xff00) >> 7) + + (rgb & 0xff); + + return gray >> (10 - image_info->x_visual_info->depth); + } + + return pixel; +} + +/** + * xlib_rgb_gc_set_foreground: + * @gc: A graphic context. + * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB. + * + * This is a convenience function to set the foreground of a GC from an RGB + * triplet. It calls xlib_rgb_xpixel_from_rgb() internally and uses the + * returned pixel value to set the GC's foreground. + **/ +void +xlib_rgb_gc_set_foreground (GC gc, unsigned int rgb) +{ + unsigned long color; + + color = xlib_rgb_xpixel_from_rgb (rgb); + XSetForeground(image_info->display, gc, color); +} + +/** + * xlib_rgb_gc_set_background: + * @gc: A graphic context. + * @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB. + * + * This is a convenience function to set the background of a GC from an RGB + * triplet. It calls xlib_rgb_xpixel_from_rgb() internally and uses the + * returned pixel value to set the GC's background. + **/ +void +xlib_rgb_gc_set_background (GC gc, unsigned int rgb) +{ + unsigned long color; + + color = xlib_rgb_xpixel_from_rgb (rgb); + XSetBackground(image_info->display, gc, color); +} + +#if KSVG_BYTE_ORDER == KSVG_LITTLE_ENDIAN +#define HAIRY_CONVERT_8 +#endif + +#ifdef HAIRY_CONVERT_8 +static void +xlib_rgb_convert_8 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + unsigned int r1b0g0r0; + unsigned int g2r2b1g1; + unsigned int b3g3r3b2; + + r1b0g0r0 = ((unsigned int *)bp2)[0]; + g2r2b1g1 = ((unsigned int *)bp2)[1]; + b3g3r3b2 = ((unsigned int *)bp2)[2]; + ((unsigned int *)obptr)[0] = + colorcube[((r1b0g0r0 & 0xf0) << 4) | + ((r1b0g0r0 & 0xf000) >> 8) | + ((r1b0g0r0 & 0xf00000) >> 20)] | + (colorcube[((r1b0g0r0 & 0xf0000000) >> 20) | + (g2r2b1g1 & 0xf0) | + ((g2r2b1g1 & 0xf000) >> 12)] << 8) | + (colorcube[((g2r2b1g1 & 0xf00000) >> 12) | + ((g2r2b1g1 & 0xf0000000) >> 24) | + ((b3g3r3b2 & 0xf0) >> 4)] << 16) | + (colorcube[((b3g3r3b2 & 0xf000) >> 4) | + ((b3g3r3b2 & 0xf00000) >> 16) | + (b3g3r3b2 >> 28)] << 24); + bp2 += 12; + obptr += 4; + } + for (; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +xlib_rgb_convert_8 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = colorcube[((r & 0xf0) << 4) | + (g & 0xf0) | + (b >> 4)]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +#if 1 + +/* This dither table was generated by Raph Levien using patented + technology (US Patent 5,276,535). The dither table itself is in the + public domain. */ + +#define DM_WIDTH 128 +#define DM_WIDTH_SHIFT 7 +#define DM_HEIGHT 128 +static const unsigned char DM[128][128] = +{ + { 0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, 4, 51, 12, 46, 35, 49, 16, 42, 12, 62 }, + { 30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39 }, + { 22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, 14, 6, 56, 38, 19, 52, 4, 46 }, + { 48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7 }, + { 18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, 23, 10, 58, 34, 43, 15, 37, 26, 33 }, + { 51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, 50, 42, 17, 5, 28, 62, 20, 54, 12 }, + { 26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, 0, 61, 53, 40, 8, 45, 2, 41 }, + { 16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57 }, + { 50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, 47, 11, 38, 3, 51, 32, 48, 18, 9 }, + { 0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55 }, + { 44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, 32, 16, 56, 6, 62, 46, 39, 60, 23 }, + { 7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, 44, 5, 37, 21, 34, 1, 26, 10, 37 }, + { 53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, 61, 23, 49, 59, 15, 53, 19, 58, 42, 16 }, + { 20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, 28, 10, 41, 30, 50, 8, 31, 57 }, + { 49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3 }, + { 41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, 12, 25, 60, 22, 52, 15, 63, 29 }, + { 20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47 }, + { 0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, 49, 21, 2, 46, 7, 53, 33, 61, 27, 35 }, + { 41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, 12, 34, 51, 16, 57, 11, 25, 17, 54, 13 }, + { 60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21 }, + { 10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, 54, 31, 62, 22, 1, 59, 30, 4, 51 }, + { 36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, 36, 43, 14, 5, 50, 38, 14, 56, 40, 23 }, + { 61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, 27, 17, 47, 34, 19, 45, 27, 12, 33, 17 }, + { 5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, 61, 0, 56, 24, 53, 3, 63, 6, 42, 57 }, + { 13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, 20, 39, 29, 8, 41, 16, 36, 52, 22, 19 }, + { 55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, 13, 59, 25, 47, 32, 1, 49, 30 }, + { 9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41 }, + { 62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, 26, 57, 2, 37, 54, 18, 44, 58, 16 }, + { 5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, 51, 15, 42, 22, 50, 10, 39, 4, 31, 35 }, + { 46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, 18, 63, 12, 29, 48, 24, 59, 20 }, + { 13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, 56, 10, 38, 0, 34, 55, 15, 43, 1, 52 }, + { 42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, 31, 58, 46, 27, 6, 61, 8, 37, 28 }, + { 0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56 }, + { 45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, 55, 35, 60, 14, 54, 4, 40, 16, 33 }, + { 27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11 }, + { 44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53 }, + { 17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, 18, 52, 22, 1, 39, 30, 58, 21 }, + { 13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41 }, + { 32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, 4, 13, 44, 28, 15, 32, 45, 19, 27, 49 }, + { 63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, 25, 37, 10, 57, 5, 37, 60, 8 }, + { 20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43 }, + { 0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, 15, 40, 21, 8, 34, 3, 41, 30, 50 }, + { 39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, 62, 45, 27, 31, 53, 17, 49, 12, 62, 18 }, + { 28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, 35, 11, 59, 42, 2, 60, 26, 46, 6, 35 }, + { 4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, 4, 16, 36, 12, 32, 56, 22, 54 }, + { 51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, 29, 39, 22, 52, 44, 20, 48, 1, 38, 14 }, + { 15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, 6, 56, 30, 7, 58, 9, 40, 19, 63 }, + { 10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, 33, 41, 14, 25, 37, 53, 29, 31, 45 }, + { 56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24 }, + { 0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, 57, 20, 34, 27, 43, 8, 59, 39 }, + { 18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, 28, 47, 13, 60, 23, 45, 13, 33 }, + { 55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22 }, + { 36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, 24, 55, 31, 19, 49, 11, 26 }, + { 2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, 50, 40, 7, 35, 15, 41, 63, 6, 40, 54 }, + { 62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17 }, + { 5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, 30, 18, 50, 34, 59, 25, 14, 44 }, + { 20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, 47, 25, 59, 42, 12, 54, 21, 3, 38, 57 }, + { 48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, 35, 10, 17, 36, 23, 1, 45, 52, 32, 10 }, + { 37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, 43, 53, 7, 57, 39, 27, 12, 61, 24 }, + { 56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, 3, 29, 48, 33, 5, 63, 16, 41, 7 }, + { 22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, 18, 54, 40, 13, 20, 46, 35, 19, 49, 29 }, + { 61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, 27, 6, 60, 52, 25, 9, 55, 1, 40 }, + { 8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, 50, 21, 33, 15, 2, 44, 31, 14, 47 }, + { 37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, 63, 45, 0, 42, 58, 37, 61, 22, 54, 26 }, + { 0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59 }, + { 44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, 14, 4, 51, 39, 49, 18, 56, 42, 20 }, + { 14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51 }, + { 28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, 11, 59, 29, 62, 1, 53, 10, 60, 33 }, + { 12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, 26, 51, 3, 24, 43, 34, 16, 41, 18, 48 }, + { 62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2 }, + { 37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, 15, 60, 6, 37, 46, 4, 50, 9, 45 }, + { 19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, 31, 49, 27, 14, 62, 22, 53, 29 }, + { 46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, 28, 53, 19, 0, 58, 32, 41, 7, 26, 13 }, + { 0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, 5, 45, 38, 24, 43, 10, 19, 54, 39, 61 }, + { 41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, 12, 63, 9, 52, 16, 56, 36, 2, 31, 16 }, + { 52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, 42, 17, 35, 27, 48, 5, 25, 50, 44, 11 }, + { 35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, 59, 30, 2, 61, 21, 33, 63, 12, 18, 59 }, + { 3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, 40, 50, 13, 44, 8, 38, 33, 46, 23 }, + { 55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29 }, + { 9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, 37, 7, 18, 47, 24, 14, 53, 42 }, + { 61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26 }, + { 0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, 21, 0, 49, 10, 60, 4, 51, 9, 45 }, + { 19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, 40, 55, 25, 34, 27, 56, 30, 32, 54 }, + { 63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, 32, 8, 17, 45, 5, 48, 18, 3, 43, 11 }, + { 21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, 60, 37, 22, 62, 12, 39, 59, 16, 52 }, + { 47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, 56, 30, 2, 53, 14, 41, 23, 34, 8, 31 }, + { 12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57 }, + { 61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, 10, 52, 7, 20, 46, 9, 38, 17 }, + { 6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, 63, 29, 61, 17, 40, 55, 22, 62, 28, 44 }, + { 20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51 }, + { 42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30 }, + { 4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, 13, 38, 19, 34, 5, 41, 25, 60 }, + { 39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17 }, + { 3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, 35, 53, 25, 3, 42, 23, 44, 32, 7, 53 }, + { 22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35 }, + { 63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, 45, 31, 57, 8, 36, 13, 58, 38, 11, 19 }, + { 0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, 21, 28, 61, 32, 6, 49, 28, 46 }, + { 58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13 }, + { 25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, 61, 40, 11, 52, 2, 60, 40, 4, 37 }, + { 52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17 }, + { 46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, 39, 5, 26, 45, 55, 18, 62, 7 }, + { 20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, 44, 3, 22, 49, 63, 12, 33, 1, 43, 31 }, + { 36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57 }, + { 53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, 39, 10, 47, 27, 37, 23, 4, 59, 38, 10 }, + { 23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, 59, 0, 52, 61, 15, 44, 19, 30, 49 }, + { 0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41 }, + { 56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, 45, 25, 12, 50, 32, 2, 28, 11, 62, 14 }, + { 44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22 }, + { 5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, 58, 5, 26, 13, 20, 2, 34, 54 }, + { 30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47 }, + { 25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, 30, 60, 0, 50, 16, 7, 29, 42, 17 }, + { 32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, 38, 14, 40, 22, 45, 36, 53, 3, 57 }, + { 44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19 }, + { 0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, 48, 3, 58, 33, 18, 61, 34, 13, 59 }, + { 39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, 42, 11, 49, 1, 27, 40, 6, 30 }, + { 24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46 }, + { 52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, 51, 34, 6, 55, 5, 63, 20, 41, 21, 9 }, + { 30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34 }, + { 3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48 }, + { 57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, 48, 0, 56, 36, 25, 8, 44, 39, 17 }, + { 10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, 13, 19, 53, 31, 3, 47, 15, 56, 22, 51 }, + { 35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, 45, 10, 41, 20, 60, 37, 5, 32, 0 }, + { 63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, 59, 2, 63, 23, 52, 11, 26, 61, 44, 23 }, + { 11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47 }, + { 39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, 16, 44, 22, 47, 28, 58, 1, 49, 54, 29 }, + { 58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, 61, 9, 52, 18, 31, 21, 36, 17 }, + { 19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5 }, + { 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 }, +}; + +#else +#define DM_WIDTH 8 +#define DM_WIDTH_SHIFT 3 +#define DM_HEIGHT 8 +static const unsigned char DM[8][8] = +{ + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } +}; +#endif + +static unsigned int *DM_565 = NULL; + +static void +xlib_rgb_preprocess_dm_565 (void) +{ + int i; + unsigned int dith; + + if (DM_565 == NULL) + { + DM_565 = malloc(sizeof(unsigned int) * DM_WIDTH * DM_HEIGHT); + for (i = 0; i < DM_WIDTH * DM_HEIGHT; i++) + { + dith = DM[0][i] >> 3; + DM_565[i] = (dith << 20) | dith | (((7 - dith) >> 1) << 10); +#ifdef VERBOSE + printf ("%i %x %x\n", i, dith, DM_565[i]); +#endif + } + } +} + +static void +xlib_rgb_convert_8_d666 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int dith; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7; + r = ((r * 5) + dith) >> 8; + g = ((g * 5) + (262 - dith)) >> 8; + b = ((b * 5) + dith) >> 8; + obptr[0] = colorcube_d[(r << 6) | (g << 3) | b]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_8_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int dith; + int rs, gs, bs; + + bptr = buf; + bpl = image->bytes_per_line; + rs = image_info->nred_shades - 1; + gs = image_info->ngreen_shades - 1; + bs = image_info->nblue_shades - 1; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7; + r = ((r * rs) + dith) >> 8; + g = ((g * gs) + (262 - dith)) >> 8; + b = ((b * bs) + dith) >> 8; + obptr[0] = colorcube_d[(r << 6) | (g << 3) | b]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_8_indexed (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + unsigned char c; + unsigned char *lut; + + lut = cmap->lut; + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + c = *bp2++; + obptr[0] = lut[c]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_gray8 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = (g + ((b + r) >> 1)) >> 1; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_gray8_gray (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int y; + int bpl; + unsigned char *obuf; + unsigned char *bptr; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + memcpy (obuf, bptr, (unsigned int)width); + bptr += rowstride; + obuf += bpl; + } +} + +#if KSVG_BYTE_ORDER == KSVG_LITTLE_ENDIAN +#define HAIRY_CONVERT_565 +#endif + +#ifdef HAIRY_CONVERT_565 +/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. + This assumes native byte ordering - what should really be done is to + check whether static_image->byte_order is consistent with the _ENDIAN + config flag, and if not, use a different function. + + This one is even faster than the one below - its inner loop loads 3 + words (i.e. 4 24-bit pixels), does a lot of shifting and masking, + then writes 2 words. */ +static void +xlib_rgb_convert_565 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + unsigned char r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obptr)[0] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + obptr += 2; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + unsigned int r1b0g0r0; + unsigned int g2r2b1g1; + unsigned int b3g3r3b2; + + r1b0g0r0 = ((unsigned int *)bp2)[0]; + g2r2b1g1 = ((unsigned int *)bp2)[1]; + b3g3r3b2 = ((unsigned int *)bp2)[2]; + ((unsigned int *)obptr)[0] = + ((r1b0g0r0 & 0xf8) << 8) | + ((r1b0g0r0 & 0xfc00) >> 5) | + ((r1b0g0r0 & 0xf80000) >> 19) | + (r1b0g0r0 & 0xf8000000) | + ((g2r2b1g1 & 0xfc) << 19) | + ((g2r2b1g1 & 0xf800) << 5); + ((unsigned int *)obptr)[1] = + ((g2r2b1g1 & 0xf80000) >> 8) | + ((g2r2b1g1 & 0xfc000000) >> 21) | + ((b3g3r3b2 & 0xf8) >> 3) | + ((b3g3r3b2 & 0xf800) << 16) | + ((b3g3r3b2 & 0xfc0000) << 3) | + ((b3g3r3b2 & 0xf8000000) >> 11); + bp2 += 12; + obptr += 8; + } + for (; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obptr)[0] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. + This assumes native byte ordering - what should really be done is to + check whether static_image->byte_order is consistent with the _ENDIAN + config flag, and if not, use a different function. + + This routine is faster than the one included with Gtk 1.0 for a number + of reasons: + + 1. Shifting instead of lookup tables (less memory traffic). + + 2. Much less register pressure, especially because shifts are + in the code. + + 3. A memcpy is avoided (i.e. the transfer function). + + 4. On big-endian architectures, byte swapping is avoided. + + That said, it wouldn't be hard to make it even faster - just make an + inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of + shifting and masking, then writes 2 words. +*/ +static void +xlib_rgb_convert_565 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + unsigned char r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obuf)[x] = ((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (b >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +#ifdef HAIRY_CONVERT_565 +static void +xlib_rgb_convert_565_gray (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + unsigned char g; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + g = *bp2++; + ((unsigned short *)obptr)[0] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + obptr += 2; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + unsigned int g3g2g1g0; + + g3g2g1g0 = ((unsigned int *)bp2)[0]; + ((unsigned int *)obptr)[0] = + ((g3g2g1g0 & 0xf8) << 8) | + ((g3g2g1g0 & 0xfc) << 3) | + ((g3g2g1g0 & 0xf8) >> 3) | + (g3g2g1g0 & 0xf800) << 16 | + ((g3g2g1g0 & 0xfc00) << 11) | + ((g3g2g1g0 & 0xf800) << 5); + ((unsigned int *)obptr)[1] = + ((g3g2g1g0 & 0xf80000) >> 8) | + ((g3g2g1g0 & 0xfc0000) >> 13) | + ((g3g2g1g0 & 0xf80000) >> 19) | + (g3g2g1g0 & 0xf8000000) | + ((g3g2g1g0 & 0xfc000000) >> 5) | + ((g3g2g1g0 & 0xf8000000) >> 11); + bp2 += 4; + obptr += 8; + } + for (; x < width; x++) + { + g = *bp2++; + ((unsigned short *)obptr)[0] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +xlib_rgb_convert_565_gray (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + unsigned char g; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + g = *bp2++; + ((unsigned short *)obuf)[x] = ((g & 0xf8) << 8) | + ((g & 0xfc) << 3) | + (g >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +static void +xlib_rgb_convert_565_br (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + unsigned char r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + /* final word is: + g4 g3 g2 b7 b6 b5 b4 b3 r7 r6 r5 r4 r3 g7 g6 g5 + */ + ((unsigned short *)obuf)[x] = (r & 0xf8) | + ((g & 0xe0) >> 5) | + ((g & 0x1c) << 11) | + ((b & 0xf8) << 5); + } + bptr += rowstride; + obuf += bpl; + } +} + +/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup + in this mode. */ +#ifdef HAIRY_CONVERT_565 +static void +xlib_rgb_convert_565_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + /* Now this is what I'd call some highly tuned code! */ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + + width += x_align; + height += y_align; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = y_align; y < height; y++) + { + unsigned int *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT); + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = x_align; x < width; x++) + { + int rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obptr)[0] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + obptr += 2; + } + } + else + { + for (x = x_align; x < width - 3; x += 4) + { + unsigned int r1b0g0r0; + unsigned int g2r2b1g1; + unsigned int b3g3r3b2; + unsigned int rgb02, rgb13; + + r1b0g0r0 = ((unsigned int *)bp2)[0]; + g2r2b1g1 = ((unsigned int *)bp2)[1]; + b3g3r3b2 = ((unsigned int *)bp2)[2]; + rgb02 = + ((r1b0g0r0 & 0xff) << 20) + + ((r1b0g0r0 & 0xff00) << 2) + + ((r1b0g0r0 & 0xff0000) >> 16) + + dmp[x & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((r1b0g0r0 & 0xff000000) >> 4) + + ((g2r2b1g1 & 0xff) << 10) + + ((g2r2b1g1 & 0xff00) >> 8) + + dmp[(x + 1) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((unsigned int *)obptr)[0] = + ((rgb02 & 0x0f800000) >> 12) | + ((rgb02 & 0x0003f000) >> 7) | + ((rgb02 & 0x000000f8) >> 3) | + ((rgb13 & 0x0f800000) << 4) | + ((rgb13 & 0x0003f000) << 9) | + ((rgb13 & 0x000000f8) << 13); + rgb02 = + ((g2r2b1g1 & 0xff0000) << 4) + + ((g2r2b1g1 & 0xff000000) >> 14) + + (b3g3r3b2 & 0xff) + + dmp[(x + 2) & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((b3g3r3b2 & 0xff00) << 12) + + ((b3g3r3b2 & 0xff0000) >> 6) + + ((b3g3r3b2 & 0xff000000) >> 24) + + dmp[(x + 3) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((unsigned int *)obptr)[1] = + ((rgb02 & 0x0f800000) >> 12) | + ((rgb02 & 0x0003f000) >> 7) | + ((rgb02 & 0x000000f8) >> 3) | + ((rgb13 & 0x0f800000) << 4) | + ((rgb13 & 0x0003f000) << 9) | + ((rgb13 & 0x000000f8) << 13); + bp2 += 12; + obptr += 8; + } + for (; x < width; x++) + { + int rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obptr)[0] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + obptr += 2; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +xlib_rgb_convert_565_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr; + + width += x_align; + height += y_align; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + (ax - x_align) * 2; + + for (y = y_align; y < height; y++) + { + unsigned int *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT); + unsigned char *bp2 = bptr; + + for (x = x_align; x < width; x++) + { + int rgb = *bp2++ << 20; + rgb += *bp2++ << 10; + rgb += *bp2++; + rgb += dmp[x & (DM_WIDTH - 1)]; + rgb += 0x10040100 + - ((rgb & 0x1e0001e0) >> 5) + - ((rgb & 0x00070000) >> 6); + + ((unsigned short *)obuf)[x] = + ((rgb & 0x0f800000) >> 12) | + ((rgb & 0x0003f000) >> 7) | + ((rgb & 0x000000f8) >> 3); + } + + bptr += rowstride; + obuf += bpl; + } +} +#endif + +static void +xlib_rgb_convert_555 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + unsigned char r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + ((unsigned short *)obuf)[x] = ((r & 0xf8) << 7) | + ((g & 0xf8) << 2) | + (b >> 3); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_555_br (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + unsigned char r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + /* final word is: + g5 g4 g3 b7 b6 b5 b4 b3 0 r7 r6 r5 r4 r3 g7 g6 + */ + ((unsigned short *)obuf)[x] = ((r & 0xf8) >> 1) | + ((g & 0xc0) >> 6) | + ((g & 0x18) << 10) | + ((b & 0xf8) << 5); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_888_msb (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int y; + unsigned char *obuf; + int bpl; + unsigned char *bptr; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3; + for (y = 0; y < height; y++) + { + memcpy (obuf, bptr, (unsigned int)(width + width + width)); + bptr += rowstride; + obuf += bpl; + } +} + +/* todo: optimize this */ +#if KSVG_BYTE_ORDER == KSVG_LITTLE_ENDIAN +#define HAIRY_CONVERT_888 +#endif + +#ifdef HAIRY_CONVERT_888 +static void +xlib_rgb_convert_888_lsb (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + if (((unsigned long)obuf | (unsigned long) bp2) & 3) + { + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + *obptr++ = b; + *obptr++ = g; + *obptr++ = r; + bp2 += 3; + } + } + else + { + for (x = 0; x < width - 3; x += 4) + { + unsigned int r1b0g0r0; + unsigned int g2r2b1g1; + unsigned int b3g3r3b2; + + r1b0g0r0 = ((unsigned int *)bp2)[0]; + g2r2b1g1 = ((unsigned int *)bp2)[1]; + b3g3r3b2 = ((unsigned int *)bp2)[2]; + ((unsigned int *)obptr)[0] = + (r1b0g0r0 & 0xff00) | + ((r1b0g0r0 & 0xff0000) >> 16) | + (((g2r2b1g1 & 0xff00) | (r1b0g0r0 & 0xff)) << 16); + ((unsigned int *)obptr)[1] = + (g2r2b1g1 & 0xff0000ff) | + ((r1b0g0r0 & 0xff000000) >> 16) | + ((b3g3r3b2 & 0xff) << 16); + ((unsigned int *)obptr)[2] = + (((g2r2b1g1 & 0xff0000) | (b3g3r3b2 & 0xff000000)) >> 16) | + ((b3g3r3b2 & 0xff00) << 16) | + ((b3g3r3b2 & 0xff0000)); + bp2 += 12; + obptr += 12; + } + for (; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + *obptr++ = b; + *obptr++ = g; + *obptr++ = r; + bp2 += 3; + } + } + bptr += rowstride; + obuf += bpl; + } +} +#else +static void +xlib_rgb_convert_888_lsb (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + obuf[x * 3] = b; + obuf[x * 3 + 1] = g; + obuf[x * 3 + 2] = r; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} +#endif + +/* convert 24-bit packed to 32-bit unpacked */ +/* todo: optimize this */ +static void +xlib_rgb_convert_0888 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((unsigned int *)obuf)[x] = (r << 16) | (g << 8) | b; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_0888_br (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((unsigned int *)obuf)[x] = (b << 24) | (g << 16) | (r << 8); + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_8880_br (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + ((unsigned int *)obuf)[x] = (b << 16) | (g << 8) | r; + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* Generic truecolor/directcolor conversion function. Slow, but these + are oddball modes. */ +static void +xlib_rgb_convert_truecolor_lsb (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + int r_right, r_left; + int g_right, g_left; + int b_right, b_left; + int bpp; + unsigned int pixel; + int i; + + r_right = 8 - image_info->red_prec; + r_left = image_info->red_shift; + g_right = 8 - image_info->green_prec; + g_left = image_info->green_shift; + b_right = 8 - image_info->blue_prec; + b_left = image_info->blue_shift; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp; + for (y = 0; y < height; y++) + { + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + pixel = ((r >> r_right) << r_left) | + ((g >> g_right) << g_left) | + ((b >> b_right) << b_left); + for (i = 0; i < bpp; i++) + { + *obptr++ = pixel & 0xff; + pixel >>= 8; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_truecolor_lsb_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + int r_right, r_left, r_prec; + int g_right, g_left, g_prec; + int b_right, b_left, b_prec; + int bpp; + unsigned int pixel; + int i; + int dith; + int r1, g1, b1; + const unsigned char *dmp; + + r_right = 8 - image_info->red_prec; + r_left = image_info->red_shift; + r_prec = image_info->red_prec; + g_right = 8 - image_info->green_prec; + g_left = image_info->green_shift; + g_prec = image_info->green_prec; + b_right = 8 - image_info->blue_prec; + b_left = image_info->blue_shift; + b_prec = image_info->blue_prec; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2; + r1 = r + (dith >> r_prec); + g1 = g + ((252 - dith) >> g_prec); + b1 = b + (dith >> b_prec); + pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) | + (((g1 - (g1 >> g_prec)) >> g_right) << g_left) | + (((b1 - (b1 >> b_prec)) >> b_right) << b_left); + for (i = 0; i < bpp; i++) + { + *obptr++ = pixel & 0xff; + pixel >>= 8; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_truecolor_msb (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + int r_right, r_left; + int g_right, g_left; + int b_right, b_left; + int bpp; + unsigned int pixel; + int shift, shift_init; + + r_right = 8 - image_info->red_prec; + r_left = image_info->red_shift; + g_right = 8 - image_info->green_prec; + g_left = image_info->green_shift; + b_right = 8 - image_info->blue_prec; + b_left = image_info->blue_shift; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp; + shift_init = (bpp - 1) << 3; + for (y = 0; y < height; y++) + { + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + pixel = ((r >> r_right) << r_left) | + ((g >> g_right) << g_left) | + ((b >> b_right) << b_left); + for (shift = shift_init; shift >= 0; shift -= 8) + { + *obptr++ = (pixel >> shift) & 0xff; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_truecolor_msb_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *obuf, *obptr; + int bpl; + unsigned char *bptr, *bp2; + int r, g, b; + int r_right, r_left, r_prec; + int g_right, g_left, g_prec; + int b_right, b_left, b_prec; + int bpp; + unsigned int pixel; + int shift, shift_init; + int dith; + int r1, g1, b1; + const unsigned char *dmp; + + r_right = 8 - image_info->red_prec; + r_left = image_info->red_shift; + r_prec = image_info->red_prec; + g_right = 8 - image_info->green_prec; + g_left = image_info->green_shift; + g_prec = image_info->green_prec; + b_right = 8 - image_info->blue_prec; + b_left = image_info->blue_shift; + b_prec = image_info->blue_prec; + bpp = image_info->bpp; + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp; + shift_init = (bpp - 1) << 3; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + obptr = obuf; + bp2 = bptr; + for (x = 0; x < width; x++) + { + r = bp2[0]; + g = bp2[1]; + b = bp2[2]; + dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2; + r1 = r + (dith >> r_prec); + g1 = g + ((252 - dith) >> g_prec); + b1 = b + (dith >> b_prec); + pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) | + (((g1 - (g1 >> g_prec)) >> g_right) << g_left) | + (((b1 - (b1 >> b_prec)) >> b_right) << b_left); + for (shift = shift_init; shift >= 0; shift -= 8) + { + *obptr++ = (pixel >> shift) & 0xff; + } + bp2 += 3; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +xlib_rgb_convert_4 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int dith; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x += 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; + obptr[0] = colorcube_d[(((r + dith) & 0x100) >> 2) | + (((g + 258 - dith) & 0x100) >> 5) | + (((b + dith) & 0x100) >> 8)]; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +xlib_rgb_convert_gray4 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + int shift; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + shift = 9 - image_info->x_visual_info->depth; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + obptr[0] = (g + ((b + r) >> 1)) >> shift; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_gray4_pack (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + int shift; + unsigned char pix0, pix1; + /* todo: this is hardcoded to big-endian. Make endian-agile. */ + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1); + shift = 9 - image_info->x_visual_info->depth; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x += 2) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix0 = (g + ((b + r) >> 1)) >> shift; + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix1 = (g + ((b + r) >> 1)) >> shift; + obptr[0] = (pix0 << 4) | pix1; + obptr++; + } + if (width & 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + pix0 = (g + ((b + r) >> 1)) >> shift; + obptr[0] = (pix0 << 4); + } + bptr += rowstride; + obuf += bpl; + } +} + +/* This actually works for depths from 3 to 7 */ +static void +xlib_rgb_convert_gray4_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int prec, right; + int gray; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + ax; + prec = image_info->x_visual_info->depth; + right = 8 - prec; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; + obptr[0] = (gray - (gray >> prec)) >> right; + obptr++; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_gray4_d_pack (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int prec, right; + int gray; + unsigned char pix0, pix1; + /* todo: this is hardcoded to big-endian. Make endian-agile. */ + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1); + prec = image_info->x_visual_info->depth; + right = 8 - prec; + for (y = 0; y < height; y++) + { + bp2 = bptr; + obptr = obuf; + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + for (x = 0; x < width; x += 2) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; + pix0 = (gray - (gray >> prec)) >> right; + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + pix1 = (gray - (gray >> prec)) >> right; + obptr[0] = (pix0 << 4) | pix1; + obptr++; + } + if (width & 1) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + gray = (g + ((b + r) >> 1)) >> 1; + gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + pix0 = (gray - (gray >> prec)) >> right; + obptr[0] = (pix0 << 4); + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +xlib_rgb_convert_1 (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + int x, y; + int bpl; + unsigned char *obuf, *obptr; + unsigned char *bptr, *bp2; + int r, g, b; + const unsigned char *dmp; + int dith; + unsigned char byte; + + bptr = buf; + bpl = image->bytes_per_line; + obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 3); + byte = 0; /* unnecessary, but it keeps gcc from complaining */ + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + for (x = 0; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 4) | 4; + byte += byte + (r + g + g + b + dith > 1020); + if ((x & 7) == 7) + { + obptr[0] = byte; + obptr++; + } + } + if (x & 7) + obptr[0] = byte << (8 - (x & 7)); + bptr += rowstride; + obuf += bpl; + } +} + +/* Returns a pointer to the stage buffer. */ +static unsigned char * +xlib_rgb_ensure_stage (void) +{ + if (image_info->stage_buf == NULL) + image_info->stage_buf = malloc (IMAGE_HEIGHT * STAGE_ROWSTRIDE); + return image_info->stage_buf; +} + +/* This is slow. Speed me up, please. */ +static void +xlib_rgb_32_to_stage (unsigned char *buf, int rowstride, int width, int height) +{ + int x, y; + unsigned char *pi_start, *po_start; + unsigned char *pi, *po; + + pi_start = buf; + po_start = xlib_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + *po++ = *pi++; + *po++ = *pi++; + *po++ = *pi++; + pi++; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic 32bit RGB conversion function - convert to 24bit packed, then + go from there. */ +static void +xlib_rgb_convert_32_generic (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + xlib_rgb_32_to_stage (buf, rowstride, width, height); + + (*image_info->conv) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Generic 32bit RGB conversion function - convert to 24bit packed, then + go from there. */ +static void +xlib_rgb_convert_32_generic_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + xlib_rgb_32_to_stage (buf, rowstride, width, height); + + (*image_info->conv_d) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* This is slow. Speed me up, please. */ +static void +xlib_rgb_gray_to_stage (unsigned char *buf, int rowstride, int width, int height) +{ + int x, y; + unsigned char *pi_start, *po_start; + unsigned char *pi, *po; + unsigned char gray; + + pi_start = buf; + po_start = xlib_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + gray = *pi++; + *po++ = gray; + *po++ = gray; + *po++ = gray; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic gray conversion function - convert to 24bit packed, then go + from there. */ +static void +xlib_rgb_convert_gray_generic (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + xlib_rgb_gray_to_stage (buf, rowstride, width, height); + + (*image_info->conv) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +static void +xlib_rgb_convert_gray_generic_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + xlib_rgb_gray_to_stage (buf, rowstride, width, height); + + (*image_info->conv_d) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Render grayscale using indexed method. */ +static void +xlib_rgb_convert_gray_cmap (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + (*image_info->conv_indexed) (image, ax, ay, width, height, + buf, rowstride, + x_align, y_align, image_info->gray_cmap); +} + +#if 0 +static void +xlib_rgb_convert_gray_cmap_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + (*image_info->conv_indexed_d) (image, ax, ay, width, height, + buf, rowstride, + x_align, y_align, image_info->gray_cmap); +} +#endif + +/* This is slow. Speed me up, please. */ +static void +xlib_rgb_indexed_to_stage (unsigned char *buf, int rowstride, int width, int height, + XlibRgbCmap *cmap) +{ + int x, y; + unsigned char *pi_start, *po_start; + unsigned char *pi, *po; + int rgb; + + pi_start = buf; + po_start = xlib_rgb_ensure_stage (); + for (y = 0; y < height; y++) + { + pi = pi_start; + po = po_start; + for (x = 0; x < width; x++) + { + rgb = cmap->colors[*pi++]; + *po++ = rgb >> 16; + *po++ = (rgb >> 8) & 0xff; + *po++ = rgb & 0xff; + } + pi_start += rowstride; + po_start += STAGE_ROWSTRIDE; + } +} + +/* Generic gray conversion function - convert to 24bit packed, then go + from there. */ +static void +xlib_rgb_convert_indexed_generic (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, XlibRgbCmap *cmap) +{ + xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap); + + (*image_info->conv) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +static void +xlib_rgb_convert_indexed_generic_d (XImage *image, + int ax, int ay, int width, int height, + unsigned char *buf, int rowstride, + int x_align, int y_align, + XlibRgbCmap *cmap) +{ + xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap); + + (*image_info->conv_d) (image, ax, ay, width, height, + image_info->stage_buf, STAGE_ROWSTRIDE, + x_align, y_align, cmap); +} + +/* Select a conversion function based on the visual and a + representative image. */ +static void +xlib_rgb_select_conv (XImage *image, ByteOrder byte_order) +{ + int depth, byterev; + int vtype; /* visual type */ + int bpp; /* bits per pixel - from the visual */ + unsigned int red_mask, green_mask, blue_mask; + XlibRgbConvFunc conv, conv_d; + XlibRgbConvFunc conv_32, conv_32_d; + XlibRgbConvFunc conv_gray, conv_gray_d; + XlibRgbConvFunc conv_indexed, conv_indexed_d; + Bool mask_rgb, mask_bgr; + + depth = image_info->x_visual_info->depth; + bpp = image->bits_per_pixel; + if (xlib_rgb_verbose) + printf ("Chose visual 0x%x, image bpp=%d, %s first\n", + (int)image_info->x_visual_info->visual->visualid, + bpp, byte_order == LSB_FIRST ? "lsb" : "msb"); + +#if KSVG_BYTE_ORDER == KSVG_BIG_ENDIAN + byterev = (byte_order == LSB_FIRST); +#else + byterev = (byte_order == MSB_FIRST); +#endif + + vtype = image_info->x_visual_info->class; + if (vtype == DirectColor) + vtype = TrueColor; + + red_mask = image_info->x_visual_info->red_mask; + green_mask = image_info->x_visual_info->green_mask; + blue_mask = image_info->x_visual_info->blue_mask; + + mask_rgb = red_mask == 0xff0000 && green_mask == 0xff00 && blue_mask == 0xff; + mask_bgr = red_mask == 0xff && green_mask == 0xff00 && blue_mask == 0xff0000; + + conv = NULL; + conv_d = NULL; + + conv_32 = xlib_rgb_convert_32_generic; + conv_32_d = xlib_rgb_convert_32_generic_d; + + conv_gray = xlib_rgb_convert_gray_generic; + conv_gray_d = xlib_rgb_convert_gray_generic_d; + + conv_indexed = xlib_rgb_convert_indexed_generic; + conv_indexed_d = xlib_rgb_convert_indexed_generic_d; + + image_info->dith_default = FALSE; + + if (image_info->bitmap) + conv = xlib_rgb_convert_1; + else if (bpp == 16 && depth == 16 && !byterev && + red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f) + { + conv = xlib_rgb_convert_565; + conv_d = xlib_rgb_convert_565_d; + conv_gray = xlib_rgb_convert_565_gray; + xlib_rgb_preprocess_dm_565 (); + } + else if (bpp == 16 && depth == 16 && + vtype == TrueColor&& byterev && + red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f) + conv = xlib_rgb_convert_565_br; + + else if (bpp == 16 && depth == 15 && + vtype == TrueColor && !byterev && + red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f) + conv = xlib_rgb_convert_555; + + else if (bpp == 16 && depth == 15 && + vtype == TrueColor && byterev && + red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f) + conv = xlib_rgb_convert_555_br; + + /* I'm not 100% sure about the 24bpp tests - but testing will show*/ + else if (bpp == 24 && depth == 24 && vtype == TrueColor && + ((mask_rgb && byte_order == LSB_FIRST) || + (mask_bgr && byte_order == MSB_FIRST))) + conv = xlib_rgb_convert_888_lsb; + else if (bpp == 24 && depth == 24 && vtype == TrueColor && + ((mask_rgb && byte_order == MSB_FIRST) || + (mask_bgr && byte_order == LSB_FIRST))) + conv = xlib_rgb_convert_888_msb; +#if KSVG_BYTE_ORDER == KSVG_BIG_ENDIAN + else if (bpp == 32 && depth == 24 && vtype == TrueColor && + (mask_rgb && byte_order == LSB_FIRST)) + conv = xlib_rgb_convert_0888_br; + else if (bpp == 32 && depth == 24 && vtype == TrueColor && + (mask_rgb && byte_order == MSB_FIRST)) + conv = xlib_rgb_convert_0888; + else if (bpp == 32 && depth == 24 && vtype == TrueColor && + (mask_bgr && byte_order == MSB_FIRST)) + conv = xlib_rgb_convert_8880_br; +#else + else if (bpp == 32 && depth == 24 && vtype == TrueColor && + (mask_rgb && byte_order == MSB_FIRST)) + conv = xlib_rgb_convert_0888_br; + else if (bpp == 32 && (depth == 32 || depth == 24) && vtype == TrueColor && + (mask_rgb && byte_order == LSB_FIRST)) + conv = xlib_rgb_convert_0888; + else if (bpp == 32 && depth == 24 && vtype == TrueColor && + (mask_bgr && byte_order == LSB_FIRST)) + conv = xlib_rgb_convert_8880_br; +#endif + + else if (vtype == TrueColor && byte_order == LSB_FIRST) + { + conv = xlib_rgb_convert_truecolor_lsb; + conv_d = xlib_rgb_convert_truecolor_lsb_d; + } + else if (vtype == TrueColor && byte_order == MSB_FIRST) + { + conv = xlib_rgb_convert_truecolor_msb; + conv_d = xlib_rgb_convert_truecolor_msb_d; + } + else if (bpp == 8 && depth == 8 && (vtype == PseudoColor +#ifdef ENABLE_GRAYSCALE + || vtype == GrayScale +#endif + )) + { + image_info->dith_default = TRUE; + conv = xlib_rgb_convert_8; + if (vtype != GrayScale) + { + if (image_info->nred_shades == 6 && + image_info->ngreen_shades == 6 && + image_info->nblue_shades == 6) + conv_d = xlib_rgb_convert_8_d666; + else + conv_d = xlib_rgb_convert_8_d; + } + conv_indexed = xlib_rgb_convert_8_indexed; + conv_gray = xlib_rgb_convert_gray_cmap; + } + else if (bpp == 8 && depth == 8 && (vtype == StaticGray +#ifdef not_ENABLE_GRAYSCALE + || vtype == GrayScale +#endif + )) + { + conv = xlib_rgb_convert_gray8; + conv_gray = xlib_rgb_convert_gray8_gray; + } + else if (bpp == 8 && depth < 8 && depth >= 2 && + (vtype == StaticGray + || vtype == GrayScale)) + { + conv = xlib_rgb_convert_gray4; + conv_d = xlib_rgb_convert_gray4_d; + } + else if (bpp == 8 && depth < 8 && depth >= 3) + { + conv = xlib_rgb_convert_4; + } + else if (bpp == 4 && depth <= 4 && depth >= 2 && + (vtype == StaticGray + || vtype == GrayScale)) + { + conv = xlib_rgb_convert_gray4_pack; + conv_d = xlib_rgb_convert_gray4_d_pack; + } + + if (conv_d == NULL) + conv_d = conv; + + image_info->conv = conv; + image_info->conv_d = conv_d; + + image_info->conv_32 = conv_32; + image_info->conv_32_d = conv_32_d; + + image_info->conv_gray = conv_gray; + image_info->conv_gray_d = conv_gray_d; + + image_info->conv_indexed = conv_indexed; + image_info->conv_indexed_d = conv_indexed_d; +} + +static int horiz_idx; +static int horiz_y = IMAGE_HEIGHT; +static int vert_idx; +static int vert_x = IMAGE_WIDTH; +static int tile_idx; +static int tile_x = IMAGE_WIDTH; +static int tile_y1 = IMAGE_HEIGHT; +static int tile_y2 = IMAGE_HEIGHT; + +#ifdef VERBOSE +static int sincelast; +#endif + +/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful + for performance evaluation. */ + +#undef NO_FLUSH + +static int +xlib_rgb_alloc_scratch_image (void) +{ + if (static_image_idx == N_IMAGES) + { +#ifndef NO_FLUSH + XFlush(image_info->display); +#endif +#ifdef VERBOSE + printf ("flush, %d puts since last flush\n", sincelast); + sincelast = 0; +#endif + static_image_idx = 0; + horiz_y = IMAGE_HEIGHT; + vert_x = IMAGE_WIDTH; + tile_x = IMAGE_WIDTH; + tile_y1 = tile_y2 = IMAGE_HEIGHT; + } + return static_image_idx++; +} + +static XImage * +xlib_rgb_alloc_scratch (int width, int height, int *ax, int *ay) +{ + XImage *image; + int idx; + + if (width >= (IMAGE_WIDTH >> 1)) + { + if (height >= (IMAGE_HEIGHT >> 1)) + { + idx = xlib_rgb_alloc_scratch_image (); + *ax = 0; + *ay = 0; + } + else + { + if (height + horiz_y > IMAGE_HEIGHT) + { + horiz_idx = xlib_rgb_alloc_scratch_image (); + horiz_y = 0; + } + idx = horiz_idx; + *ax = 0; + *ay = horiz_y; + horiz_y += height; + } + } + else + { + if (height >= (IMAGE_HEIGHT >> 1)) + { + if (width + vert_x > IMAGE_WIDTH) + { + vert_idx = xlib_rgb_alloc_scratch_image (); + vert_x = 0; + } + idx = vert_idx; + *ax = vert_x; + *ay = 0; + /* using 3 and -4 would be slightly more efficient on 32-bit machines + with > 1bpp displays */ + vert_x += (width + 7) & -8; + } + else + { + if (width + tile_x > IMAGE_WIDTH) + { + tile_y1 = tile_y2; + tile_x = 0; + } + if (height + tile_y1 > IMAGE_HEIGHT) + { + tile_idx = xlib_rgb_alloc_scratch_image (); + tile_x = 0; + tile_y1 = 0; + tile_y2 = 0; + } + if (height + tile_y1 > tile_y2) + tile_y2 = height + tile_y1; + idx = tile_idx; + *ax = tile_x; + *ay = tile_y1; + tile_x += (width + 7) & -8; + } + } + image = static_image[idx]; +#ifdef VERBOSE + printf ("index %d, x %d, y %d (%d x %d)\n", idx, *ax, *ay, width, height); + sincelast++; +#endif + return image; +} + +static void +xlib_draw_rgb_image_core (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + unsigned char *buf, + int pixstride, + int rowstride, + XlibRgbConvFunc conv, + XlibRgbCmap *cmap, + int xdith, + int ydith) +{ + int ay, ax; + int xs0, ys0; + XImage *image; + int width1, height1; + unsigned char *buf_ptr; + + if (image_info->bitmap) + { + if (image_info->own_gc == 0) + { + XColor color; + + image_info->own_gc = XCreateGC(image_info->display, + drawable, + 0, NULL); + color.pixel = WhitePixel(image_info->display, + image_info->screen_num); + XSetForeground(image_info->display, image_info->own_gc, color.pixel); + color.pixel = BlackPixel(image_info->display, + image_info->screen_num); + XSetBackground(image_info->display, image_info->own_gc, color.pixel); + } + gc = image_info->own_gc; + } + for (ay = 0; ay < height; ay += IMAGE_HEIGHT) + { + height1 = MIN (height - ay, IMAGE_HEIGHT); + for (ax = 0; ax < width; ax += IMAGE_WIDTH) + { + width1 = MIN (width - ax, IMAGE_WIDTH); + buf_ptr = buf + ay * rowstride + ax * pixstride; + + image = xlib_rgb_alloc_scratch (width1, height1, &xs0, &ys0); + + conv (image, xs0, ys0, width1, height1, buf_ptr, rowstride, + x + ax + xdith, y + ay + ydith, cmap); + +#ifndef DONT_ACTUALLY_DRAW + XPutImage(image_info->display, drawable, gc, image, + xs0, ys0, x + ax, y + ay, (unsigned int)width1, (unsigned int)height1); +#endif + } + } +} + + +/** + * xlib_draw_rgb_image: + * @drawable: Destination drawable. + * @gc: A graphic context. + * @x: Leftmost coordinate of the destination rectangle. + * @y: Upper coordinate of the destination rectangle. + * @width: Width of the destination rectangle, in pixels. + * @height: Height of the destination rectangle, in pixels. + * @dith: Dithering method to use. + * @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the + * upper-left corner of the rectangular region to render. + * @rowstride: Offset between pixel rows in the RGB buffer, in bytes. + * + * Renders an RGB buffer to a drawable. Pixels are specified as RGB triplets + * with 8 bits per channel. An image will thus look like an RGBRGBRGBRGB + * sequence of 8-bit values. This function does not let you specify dither + * offsets; applications that need to render partial regions of a buffer to + * build the final image should use xlib_draw_rgb_image_dithalign() instead. + **/ +void +xlib_draw_rgb_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *rgb_buf, + int rowstride) +{ + if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL && + !image_info->dith_default)) + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv, NULL, + 0, 0); + else + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv_d, NULL, + 0, 0); +} + +/** + * xlib_draw_rgb_image_dithalign: + * @drawable: Destination drawable. + * @gc: A graphic context. + * @x: Leftmost coordinate of the destination rectangle. + * @y: Upper coordinate of the destination rectangle. + * @width: Width of the destination rectangle, in pixels. + * @height: Height of the destination rectangle, in pixels. + * @dith: Dithering method to use. + * @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the + * upper-left corner of the rectangular region to render. + * @rowstride: Offset between pixel rows in the RGB buffer, in bytes. + * @xdith: X offset for the dither mask. + * @ydith: Y offset for the dither mask. + * + * Renders an RGB buffer to a drawable. Pixels are specified as RGB triplets + * with 8 bits per channel. An image will thus look like an RGBRGBRGBRGB + * sequence of 8-bit values. This function lets you specify a pair of dither + * offsets. It should be used when you need to render regions of an RGB buffer + * separately to form the final image; the dither offsets let you align the + * dither mask appropriately. + **/ +void +xlib_draw_rgb_image_dithalign (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *rgb_buf, + int rowstride, + int xdith, + int ydith) +{ + if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL && + !image_info->dith_default)) + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv, NULL, + xdith, ydith); + else + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + rgb_buf, 3, rowstride, image_info->conv_d, NULL, + xdith, ydith); +} + +/** + * xlib_draw_rgb_32_image: + * @drawable: Destination drawable. + * @gc: A graphic context. + * @x: Leftmost coordinate of the destination rectangle. + * @y: Upper coordinate of the destination rectangle. + * @width: Width of the destination rectangle, in pixels. + * @height: Height of the destination rectangle, in pixels. + * @dith: Dithering method to use. + * @buf: Pointer to the pixel in the RGB buffer that corresponds to the + * upper-left corner of the rectangular region to render. + * @rowstride: Offset between pixel rows in the RGB buffer, in bytes. + * + * This function is analogous to xlib_draw_rgb_image(), but it lets you use + * 32-bit RGB buffers with pixels specified as 0xRRGGBB00. The + * least-significant 8 bits are actually discarded. This function can lead to + * faster results than xlib_draw_rgb_image() since the pixels are aligned on + * 32-bit boundaries. + **/ +void +xlib_draw_rgb_32_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride) +{ + if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL && + !image_info->dith_default)) + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 4, rowstride, + image_info->conv_32, NULL, 0, 0); + else + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 4, rowstride, + image_info->conv_32_d, NULL, 0, 0); +} + +static void +xlib_rgb_make_gray_cmap (XlibRgbInfo *info) +{ + unsigned int rgb[256]; + int i; + + for (i = 0; i < 256; i++) + rgb[i] = (i << 16) | (i << 8) | i; + info->gray_cmap = xlib_rgb_cmap_new (rgb, 256); +} + +/** + * xlib_draw_gray_image: + * @drawable: Destination drawable. + * @gc: A graphic context. + * @x: Leftmost coordinate of the destination rectangle. + * @y: Upper coordinate of the destination rectangle. + * @width: Width of the destination rectangle, in pixels. + * @height: Height of thd destination rectangle, in pixels. + * @dith: Dithering method to use. + * @buf: Pointer to the pixel in the grayscale buffer that corresponds to the + * upper-left corner of the rectangular region to render. + * @rowstride: Offset between pixel rows in the grayscale buffer, in pixels. + * + * Renders a grayscale buffer to a drawable. Pixels are specified as 8-bit + * intensity values. An image will thus look as a GGGGGG sequence of 8-bit + * values. + **/ +void +xlib_draw_gray_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride) +{ + if (image_info->bpp == 1 && + image_info->gray_cmap == NULL && + (image_info->x_visual_info->class == PseudoColor || + image_info->x_visual_info->class == GrayScale)) + xlib_rgb_make_gray_cmap (image_info); + + if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL && + !image_info->dith_default)) + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_gray, NULL, 0, 0); + else + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_gray_d, NULL, 0, 0); +} + +/** + * xlib_rgb_cmap_new: + * @colors: FIXME + * @n_colors: FIXME + * + * FIXME + * + * Return value: FIXME + **/ +XlibRgbCmap * +xlib_rgb_cmap_new (unsigned int *colors, int n_colors) +{ + XlibRgbCmap *cmap; + int i, j; + unsigned int rgb; + + if (n_colors < 0) + return NULL; + if (n_colors > 256) + return NULL; + cmap = malloc(sizeof(XlibRgbCmap)); + memcpy (cmap->colors, colors, n_colors * sizeof(unsigned int)); + if (image_info->bpp == 1 && + (image_info->x_visual_info->class == PseudoColor || + image_info->x_visual_info->class == GrayScale)) + for (i = 0; i < n_colors; i++) + { + rgb = colors[i]; + j = ((rgb & 0xf00000) >> 12) | + ((rgb & 0xf000) >> 8) | + ((rgb & 0xf0) >> 4); +#ifdef VERBOSE + printf ("%d %x %x %d\n", i, j, colorcube[j]); +#endif + cmap->lut[i] = colorcube[j]; + } + return cmap; +} + +/** + * xlib_rgb_cmap_free: + * @cmap: An XlibRGB colormap. + * + * Frees an XlibRGB colormap. + **/ +void +xlib_rgb_cmap_free (XlibRgbCmap *cmap) +{ + free (cmap); +} + +/** + * xlib_draw_indexed_image: + * @drawable: FIXME + * @gc: FIXME + * @x: FIXME + * @y: FIXME + * @width: FIXME + * @height: FIXME + * @dith: FIXME + * @buf: FIXME + * @rowstride: FIXME + * @cmap: FIXME + * + * FIXME + **/ +void +xlib_draw_indexed_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride, + XlibRgbCmap *cmap) +{ + if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL && + !image_info->dith_default)) + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_indexed, cmap, 0, 0); + else + xlib_draw_rgb_image_core (drawable, gc, x, y, width, height, + buf, 1, rowstride, + image_info->conv_indexed_d, cmap, 0, 0); +} + +/** + * xlib_rgb_ditherable: + * + * Queries whether XlibRGB supports dithering for its chosen visual. + * + * Return value: TRUE if dithering can be performed for the visual that XlibRGB + * is using, FALSE otherwise. + **/ +Bool +xlib_rgb_ditherable (void) +{ + return (image_info->conv != image_info->conv_d); +} + +/** + * xlib_rgb_get_cmap: + * + * Queries the X colormap that XlibRGB is using. + * + * Return value: An X colormap. + **/ +Colormap +xlib_rgb_get_cmap (void) +{ + /* xlib_rgb_init (); */ + if (image_info) + return image_info->cmap; + else + return 0; +} + +/** + * xlib_rgb_get_visual: + * + * Queries the visual that XlibRGB is using. + * + * Return value: An X visual. + **/ +Visual * +xlib_rgb_get_visual (void) +{ + /* xlib_rgb_init (); */ + if (image_info) + return image_info->x_visual_info->visual; + else + return 0; +} + +/** + * xlib_rgb_get_visual_info: + * + * Queries the visual info structure for the visual that XlibRGB is using. + * + * Return value: An XVisualInfo structure. + **/ +XVisualInfo * +xlib_rgb_get_visual_info (void) +{ + /* xlib_rgb_init (); */ + if (image_info) + return image_info->x_visual_info; + else + return 0; +} + +/** + * xlib_rgb_get_depth: + * + * Queries the depth of the visual that XlibRGB is using. + * + * Return value: Bit depth. + **/ +int +xlib_rgb_get_depth (void) +{ + XVisualInfo * v = xlib_rgb_get_visual_info(); + + if (v) + { + return v->depth; + } + + return 0; +} + +/** + * xlib_rgb_get_display: + * + * Queries the X display that XlibRGB is using. + * + * Return value: An X display. + **/ +Display * +xlib_rgb_get_display (void) +{ + if (image_info) + return image_info->display; + + return NULL; +} + +/** + * xlib_rgb_get_screen: + * + * Queries the screen that XlibRGB is using. + * + * Return value: An X screen. + **/ +Screen * +xlib_rgb_get_screen (void) +{ + if (image_info) + return image_info->screen; + + return NULL; +} diff --git a/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.h b/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.h new file mode 100644 index 00000000..d35c1c87 --- /dev/null +++ b/karbon/render/xrgbrender/gdk-pixbuf-xlibrgb.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "MPL"); you may not use this file except in + * compliance with the MPL. You may obtain a copy of the MPL at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the MPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL + * for the specific language governing rights and limitations under the + * MPL. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Library General Public License (the "LGPL"), in + * which case the provisions of the LGPL are applicable instead of + * those above. If you wish to allow use of your version of this file + * only under the terms of the LGPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the LGPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the LGPL. + */ + +/* + * This code is derived from GdkRgb. + * For more information on GdkRgb, see http://www.levien.com/gdkrgb/ + * Raph Levien <raph@acm.org> + */ + +/* Ported by Christopher Blizzard to Xlib. With permission from the + * original authors of this file, the contents of this file are also + * redistributable under the terms of the Mozilla Public license. For + * information about the Mozilla Public License, please see the + * license information at http://www.mozilla.org/MPL/ + */ + +/* This code is copyright the following authors: + * Raph Levien <raph@acm.org> + * Manish Singh <manish@gtk.org> + * Tim Janik <timj@gtk.org> + * Peter Mattis <petm@xcf.berkeley.edu> + * Spencer Kimball <spencer@xcf.berkeley.edu> + * Josh MacDonald <jmacd@xcf.berkeley.edu> + * Christopher Blizzard <blizzard@redhat.com> + * Owen Taylor <otaylor@redhat.com> + * Shawn T. Amundson <amundson@gtk.org> +*/ + + +#ifndef __XLIB_RGB_H__ +#define __XLIB_RGB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Intrinsic.h> + + +typedef struct _XlibRgbCmap XlibRgbCmap; + +struct _XlibRgbCmap { + unsigned int colors[256]; + unsigned char lut[256]; /* for 8-bit modes */ +}; + +void +xlib_rgb_init (Display *display, Screen *screen); +void +xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth); + +unsigned long +xlib_rgb_xpixel_from_rgb (unsigned int rgb); + +void +xlib_rgb_gc_set_foreground (GC gc, unsigned int rgb); + +void +xlib_rgb_gc_set_background (GC gc, unsigned int rgb); + +typedef enum +{ + XLIB_RGB_DITHER_NONE, + XLIB_RGB_DITHER_NORMAL, + XLIB_RGB_DITHER_MAX +} XlibRgbDither; + +void +xlib_draw_rgb_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *rgb_buf, + int rowstride); + +void +xlib_draw_rgb_image_dithalign (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *rgb_buf, + int rowstride, + int xdith, + int ydith); + +void +xlib_draw_rgb_32_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride); + +void +xlib_draw_gray_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride); + +XlibRgbCmap * +xlib_rgb_cmap_new (unsigned int *colors, int n_colors); + +void +xlib_rgb_cmap_free (XlibRgbCmap *cmap); + +void +xlib_draw_indexed_image (Drawable drawable, + GC gc, + int x, + int y, + int width, + int height, + XlibRgbDither dith, + unsigned char *buf, + int rowstride, + XlibRgbCmap *cmap); + +/* Below are some functions which are primarily useful for debugging + and experimentation. */ +Bool +xlib_rgb_ditherable (void); + +void +xlib_rgb_set_verbose (Bool verbose); + +/* experimental colormap stuff */ +void +xlib_rgb_set_install (Bool install); + +void +xlib_rgb_set_min_colors (int min_colors); + +Colormap +xlib_rgb_get_cmap (void); + +Visual * +xlib_rgb_get_visual (void); + +XVisualInfo * +xlib_rgb_get_visual_info (void); + +int +xlib_rgb_get_depth (void); + +Display * +xlib_rgb_get_display (void); + +Screen * +xlib_rgb_get_screen (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __XLIB_RGB_H__ */ diff --git a/karbon/shapes/Makefile.am b/karbon/shapes/Makefile.am new file mode 100644 index 00000000..bbb7899b --- /dev/null +++ b/karbon/shapes/Makefile.am @@ -0,0 +1,29 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../commands \ + $(all_includes) + +noinst_LTLIBRARIES = libkarbonshapes.la + +noinst_HEADERS = \ + vellipse.h \ + vpolyline.h \ + vpolygon.h \ + vrectangle.h \ + vsinus.h \ + vspiral.h \ + vstar.h + +libkarbonshapes_la_SOURCES = \ + vellipse.cc \ + vpolyline.cc \ + vpolygon.cc \ + vrectangle.cc \ + vsinus.cc \ + vspiral.cc \ + vstar.cc + +libkarbonshapes_la_METASOURCES = \ + AUTO + diff --git a/karbon/shapes/vellipse.cc b/karbon/shapes/vellipse.cc new file mode 100644 index 00000000..c2afc804 --- /dev/null +++ b/karbon/shapes/vellipse.cc @@ -0,0 +1,316 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vellipse.h" +#include "vtransformcmd.h" +#include <klocale.h> +#include <KoUnit.h> +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <vglobal.h> +#include <vdocument.h> +#include <qdom.h> +#include <core/vfill.h> + +VEllipse::VEllipse( VObject* parent, VState state ) : VPath( parent, state ) +{ +} + +VEllipse::VEllipse( VObject* parent, + const KoPoint& topLeft, double width, double height, + VEllipseType type, double startAngle, double endAngle ) + : VPath( parent ), m_type( type ), m_startAngle( startAngle ), m_endAngle( endAngle ) +{ + setDrawCenterNode(); + + m_rx = width / 2.0; + m_ry = height / 2.0; + m_center.setX( topLeft.x() + m_rx ); + m_center.setY( topLeft.y() + m_ry ); + + init(); +} + +void +VEllipse::init() +{ + // to radials + int nsegs; + if( m_startAngle < m_endAngle ) + nsegs = int( floor( ( m_endAngle - m_startAngle ) / 90.0 ) ); + else + nsegs = 4 - int( ceil( ( m_startAngle - m_endAngle ) / 90.0 ) ); + double startAngle = m_startAngle - 90.0; + if( startAngle < 0 ) startAngle += 360.0; + startAngle = VGlobal::pi_2 * ( startAngle / 90.0 ); + double endAngle = m_endAngle - 90.0; + if( endAngle < 0 ) endAngle += 360.0; + endAngle = VGlobal::pi_2 * ( endAngle / 90.0 ); + // Create (half-)unity circle with topLeft at (0|0): + double currentAngle = -startAngle - VGlobal::pi_2; + KoPoint start( 0.5 * sin( -startAngle ), 0.5 * cos( -startAngle ) ); + moveTo( KoPoint( start.x(), start.y() ) ); + double midAngle = currentAngle + VGlobal::pi_2 / 2.0; + double midAmount = 0.5 / sin( VGlobal::pi_2 / 2.0 ); + for( int i = 0;i < nsegs;i++ ) + { + midAngle -= VGlobal::pi_2; + arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ), + KoPoint( 0.5 * sin( currentAngle ), 0.5 * cos( currentAngle ) ), 0.5 ); + currentAngle -= VGlobal::pi_2; + } + double rest = ( -endAngle - VGlobal::pi_2 - currentAngle ) * 90.0 / VGlobal::pi_2; + if( rest > 0 ) + rest -= 360.0; + if( rest != 0 ) + { + midAngle = currentAngle - ( -rest / 360.0 ) * VGlobal::pi; + midAmount = 0.5 / cos( currentAngle - midAngle ); + KoPoint end( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) ); + arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ), + KoPoint( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) ), 0.5 ); + } + if( m_type == cut ) + lineTo( KoPoint( 0.0, 0.0 ) ); + if( m_type != arc ) + close(); + + // Translate and scale: + QWMatrix m; + m.translate( m_center.x(), m_center.y() ); + m.scale( 2.0 * m_rx, 2.0 * m_ry ); + + // only tranform the path data + VTransformCmd cmd( 0L, m ); + cmd.VVisitor::visitVPath( *this ); + + m_matrix.reset(); +} + +QString +VEllipse::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Ellipse" ); +} + +void +VEllipse::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "ELLIPSE" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "cx", m_center.x() ); + me.setAttribute( "cy", m_center.y() ); + + me.setAttribute( "rx", m_rx ); + me.setAttribute( "ry", m_ry ); + + me.setAttribute( "start-angle", m_startAngle ); + me.setAttribute( "end-angle", m_endAngle ); + + if( m_type == cut ) + me.setAttribute( "kind", "cut" ); + else if( m_type == section ) + me.setAttribute( "kind", "section" ); + else if( m_type == arc ) + me.setAttribute( "kind", "arc" ); + else + me.setAttribute( "kind", "full" ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VEllipse::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + docWriter->startElement( "draw:ellipse" ); + + //save all into pt + docWriter->addAttributePt( "svg:cx", m_center.x() ); + docWriter->addAttributePt( "svg:cy", m_center.y() ); + docWriter->addAttributePt( "svg:rx", m_rx ); + docWriter->addAttributePt( "svg:ry", m_ry ); + + if( m_type == full ) + docWriter->addAttribute( "draw:kind", "full" ); + else + { + // the meaning of cut and section is mixed up in karbon, so just set them so for now + // be sure to do the right thing tm for karbon 2.0 + if( m_type == section ) + docWriter->addAttribute( "draw:kind", "cut" ); + else if( m_type == cut ) + docWriter->addAttribute( "draw:kind", "section" ); + else + docWriter->addAttribute( "draw:kind", "arc" ); + + docWriter->addAttribute( "draw:start-angle", m_startAngle ); + docWriter->addAttribute( "draw:end-angle", m_endAngle ); + } + + VObject::saveOasis( store, docWriter, mainStyles, index ); + + QWMatrix tmpMat; + tmpMat.scale( 1, -1 ); + tmpMat.translate( 0, -document()->height() ); + + QString transform = buildOasisTransform( m_matrix*tmpMat ); + if( !transform.isEmpty() ) + docWriter->addAttribute( "draw:transform", transform ); + + docWriter->endElement(); +} + +bool +VEllipse::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + setState( normal ); + + if( element.tagName() == "ellipse" ) + { + if( element.hasAttributeNS( KoXmlNS::svg, "rx" ) ) + m_rx = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "rx", QString::null ) ); + else + m_rx = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) ); + + if( element.hasAttributeNS( KoXmlNS::svg, "ry" ) ) + m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "ry", QString::null ) ); + else + m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) ); + + } + else if( element.tagName() == "circle" ) + { + if( element.hasAttributeNS( KoXmlNS::svg, "r" ) ) + m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "r", QString::null ) ); + else + m_rx = m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) ); + } + + if( element.hasAttributeNS( KoXmlNS::svg, "cx" ) ) + m_center.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) ); + else + m_center.setX( m_rx + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ) ); + + if( element.hasAttributeNS( KoXmlNS::svg, "cy" ) ) + m_center.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) ); + else + m_center.setY( m_ry + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ) ); + + // the meaning of cut and section is mixed up in karbon, so just set them so for now + // be sure to do the right thing tm for karbon 2.0 + QString kind = element.attributeNS( KoXmlNS::draw, "kind", QString::null ); + if( kind == "cut" ) + m_type = section; + else if( kind == "section" ) + m_type = cut; + else if( kind == "arc" ) + m_type = arc; + else + m_type = full; + + double startAngle = element.attributeNS( KoXmlNS::draw, "start-angle", QString::null ).toDouble(); + double endAngle = element.attributeNS( KoXmlNS::draw, "end-angle", QString::null ).toDouble(); + + // the shape gets mirrored in y-direction, so make the angles temporary clockwise + // just for creating the path + m_startAngle = 360.0 - endAngle; + m_endAngle = 360.0 - startAngle; + + init(); + + // now set the right angles + m_startAngle = startAngle; + m_endAngle = endAngle; + + transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) ); + + QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null ); + if( !trafo.isEmpty() ) + transformOasis( trafo ); + + return VObject::loadOasis( element, context ); +} + +void +VEllipse::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_rx = KoUnit::parseValue( element.attribute( "rx" ) ); + m_ry = KoUnit::parseValue( element.attribute( "ry" ) ); + + m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) ); + m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) ); + + m_startAngle = element.attribute( "start-angle" ).toDouble(); + m_endAngle = element.attribute( "end-angle" ).toDouble(); + + if( element.attribute( "kind" ) == "cut" ) + m_type = cut; + else if( element.attribute( "kind" ) == "section" ) + m_type = section; + else if( element.attribute( "kind" ) == "arc" ) + m_type = arc; + else + m_type = full; + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +VPath* +VEllipse::clone() const +{ + return new VEllipse( *this ); +} diff --git a/karbon/shapes/vellipse.h b/karbon/shapes/vellipse.h new file mode 100644 index 00000000..e7decbd2 --- /dev/null +++ b/karbon/shapes/vellipse.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VELLIPSE_H__ +#define __VELLIPSE_H__ + +#include "vcomposite.h" +#include <koffice_export.h> + +class KARBONBASE_EXPORT VEllipse : public VPath +{ +public: + enum VEllipseType + { + full, + section, + cut, + arc + }; + VEllipse( VObject* parent, VState state = edit ); + VEllipse( VObject* parent, + const KoPoint& topLeft, double width, double height, + VEllipseType type = full, double startAngle = 0, double endAngle = 0 ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + VEllipseType m_type; + KoPoint m_center; + double m_rx; + double m_ry; + double m_startAngle; + double m_endAngle; +}; + +#endif + diff --git a/karbon/shapes/vpolygon.cc b/karbon/shapes/vpolygon.cc new file mode 100644 index 00000000..aa74ca90 --- /dev/null +++ b/karbon/shapes/vpolygon.cc @@ -0,0 +1,185 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qdom.h> + +#include "vglobal.h" +#include "vpolygon.h" +#include "vtransformcmd.h" +#include <klocale.h> +#include <KoUnit.h> +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <vdocument.h> + +VPolygon::VPolygon( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +VPolygon::VPolygon( VObject* parent, const QString &points, + const KoPoint& topLeft, double width, double height ) + : VPath( parent ), m_topLeft( topLeft ), m_width( width), m_height( height ), m_points( points ) +{ + init(); +} + +void +VPolygon::init() +{ + bool bFirst = true; + + QString points = m_points.simplifyWhiteSpace(); + points.replace( ',', ' ' ); + points.remove( '\r' ); + points.remove( '\n' ); + QStringList pointList = QStringList::split( ' ', points ); + QStringList::Iterator end(pointList.end()); + for( QStringList::Iterator it = pointList.begin(); it != end; ++it ) + { + KoPoint point; + point.setX( (*it).toDouble() ); + point.setY( (*++it).toDouble() ); + if( bFirst ) + { + moveTo( point ); + bFirst = false; + } + else + lineTo( point ); + } + close(); + + QWMatrix m; + m.translate( m_topLeft.x(), m_topLeft.y() ); + + // only tranform the path data + VTransformCmd cmd( 0L, m ); + cmd.VVisitor::visitVPath( *this ); +} + +QString +VPolygon::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Polygon" ); +} + +void +VPolygon::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "POLYGON" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "x", m_topLeft.x() ); + me.setAttribute( "y", m_topLeft.y() ); + + me.setAttribute( "width", QString("%1pt").arg( m_width ) ); + me.setAttribute( "height", QString("%1pt").arg( m_height ) ); + + me.setAttribute( "points", m_points ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VPolygon::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + docWriter->startElement( "draw:polygon" ); + + docWriter->addAttribute( "draw:points", m_points ); + + VObject::saveOasis( store, docWriter, mainStyles, index ); + + docWriter->endElement(); +} + +void +VPolygon::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_points = element.attribute( "points" ); + + m_width = KoUnit::parseValue( element.attribute( "width" ), 10.0 ); + m_height = KoUnit::parseValue( element.attribute( "height" ), 10.0 ); + + m_topLeft.setX( KoUnit::parseValue( element.attribute( "x" ) ) ); + m_topLeft.setY( KoUnit::parseValue( element.attribute( "y" ) ) ); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +bool +VPolygon::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + setState( normal ); + + m_points = element.attributeNS( KoXmlNS::draw, "points", QString::null ); + + init(); + + transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) ); + + QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null ); + if( !trafo.isEmpty() ) + transformOasis( trafo ); + + return VObject::loadOasis( element, context ); +} + +VPath* +VPolygon::clone() const +{ + return new VPolygon( *this ); +} diff --git a/karbon/shapes/vpolygon.h b/karbon/shapes/vpolygon.h new file mode 100644 index 00000000..9b7bc940 --- /dev/null +++ b/karbon/shapes/vpolygon.h @@ -0,0 +1,52 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPOLYGON_H__ +#define __VPOLYGON_H__ + +#include "vcomposite.h" + +class VPolygon : public VPath +{ +public: + VPolygon( VObject* parent, VState state = edit ); + VPolygon( VObject* parent, const QString &points, + const KoPoint& topLeft, double width, double height ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + KoPoint m_topLeft; + double m_width; + double m_height; + QString m_points; +}; + +#endif + diff --git a/karbon/shapes/vpolyline.cc b/karbon/shapes/vpolyline.cc new file mode 100644 index 00000000..c55c0d14 --- /dev/null +++ b/karbon/shapes/vpolyline.cc @@ -0,0 +1,184 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vpolyline.h" +#include <qdom.h> + +#include "vglobal.h" +#include <klocale.h> +#include <vdocument.h> +#include "vtransformcmd.h" + +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> + +VPolyline::VPolyline( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +/*VPolyline::VPolyline( VObject* parent, VState state ) + : VPath( parent, state ) +{ +}*/ + +/*VPolyline::VPolyline( VObject* parent, const QString &points ) + : VPath( parent ), m_points( points ) +{ + init(); +}*/ + +void +VPolyline::init() +{ + bool bFirst = true; + + QString points = m_points.simplifyWhiteSpace(); + points.replace( ',', ' ' ); + points.remove( '\r' ); + points.remove( '\n' ); + QStringList pointList = QStringList::split( ' ', points ); + QStringList::Iterator end(pointList.end()); + for( QStringList::Iterator it = pointList.begin(); it != end; ++it ) + { + KoPoint point; + point.setX( (*it).toDouble() ); + point.setY( (*++it).toDouble() ); + if( bFirst ) + { + moveTo( point ); + bFirst = false; + } + else + lineTo( point ); + } +} + +QString +VPolyline::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Polyline" ); +} + +void +VPolyline::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "POLYLINE" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "points", m_points ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VPolyline::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + docWriter->startElement( "draw:polyline" ); + + docWriter->addAttribute( "svg:points", m_points ); + + VObject::saveOasis( store, docWriter, mainStyles, index ); + + docWriter->endElement(); +} + +void +VPolyline::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_points = element.attribute( "points" ); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +bool +VPolyline::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + setState( normal ); + + if( element.localName() == "line" ) + { + KoPoint p1, p2; + p1.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x1", QString::null ) ) ); + p1.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y1", QString::null ) ) ); + p2.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x2", QString::null ) ) ); + p2.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y2", QString::null ) ) ); + + m_points = QString( "%1,%2 %3,%4" ).arg( p1.x() ).arg( p1.y() ).arg( p2.x() ).arg( p2.y() ); + + moveTo( p1 ); + lineTo( p2 ); + } + else if( element.localName() == "polyline" ) + { + m_points = element.attributeNS( KoXmlNS::draw, "points", QString::null ); + init(); + } + + transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) ); + + QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null ); + if( !trafo.isEmpty() ) + transformOasis( trafo ); + + return VObject::loadOasis( element, context ); +} + +VPath* +VPolyline::clone() const +{ + return new VPolyline( *this ); +} diff --git a/karbon/shapes/vpolyline.h b/karbon/shapes/vpolyline.h new file mode 100644 index 00000000..34da9716 --- /dev/null +++ b/karbon/shapes/vpolyline.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPOLYLINE_H__ +#define __VPOLYLINE_H__ + +#include "vcomposite.h" +#include <qstring.h> + +class VPolyline : public VPath +{ +public: + VPolyline( VObject* parent, VState state = edit ); + //VPolyline( VObject* parent, VState state = edit ); + //VPolyline( VObject* parent, const QString &points ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + QString m_points; +}; + +#endif + diff --git a/karbon/shapes/vrectangle.cc b/karbon/shapes/vrectangle.cc new file mode 100644 index 00000000..966c2bb2 --- /dev/null +++ b/karbon/shapes/vrectangle.cc @@ -0,0 +1,229 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vrectangle.h" +#include <klocale.h> +#include <KoUnit.h> +#include <KoStore.h> +#include <KoXmlWriter.h> +#include <KoXmlNS.h> +#include <qdom.h> +#include <kdebug.h> +#include "vglobal.h" +#include <vdocument.h> +#include "vtransformcmd.h" + +VRectangle::VRectangle( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +VRectangle::VRectangle( VObject* parent, + const KoPoint& topLeft, double width, double height, double rx, double ry ) + : VPath( parent ), m_topLeft( topLeft ), m_width( width), m_height( height ), m_rx( rx ), m_ry( ry ) +{ + setDrawCenterNode(); + + if( m_rx < 0.0 ) m_rx = 0.0; + if( m_ry < 0.0 ) m_ry = 0.0; + // Catch case, when radius is larger than width or height: + if( m_rx > m_width * 0.5 ) + m_rx = m_width * 0.5; + if( m_ry > m_height * 0.5 ) + m_ry = m_height * 0.5; + + init(); +} + +void +VRectangle::init() +{ + if( m_rx == 0 && m_ry == 0 ) + { + moveTo( m_topLeft ); + lineTo( KoPoint( m_topLeft.x(), m_topLeft.y() - m_height ) ); + lineTo( KoPoint( m_topLeft.x() + m_width, m_topLeft.y() - m_height ) ); + lineTo( KoPoint( m_topLeft.x() + m_width, m_topLeft.y() ) ); + } + else + { + double rx = m_rx; + double ry = m_ry; + double x = m_topLeft.x(); + double y = m_topLeft.y(); + moveTo( KoPoint( x + rx, y ) ); + curveTo( KoPoint( x + rx * ( 1 - 0.552 ), y ), + KoPoint( x, y - ry * ( 1 - 0.552 ) ), + KoPoint( x, y - ry ) ); + if( ry < m_height / 2 ) + lineTo( KoPoint( x, y - m_height + ry ) ); + curveTo( KoPoint( x, y - m_height + ry * ( 1 - 0.552 ) ), + KoPoint( x + rx * ( 1 - 0.552 ), y - m_height ), + KoPoint( x + rx, y - m_height ) ); + if( rx < m_width / 2 ) + lineTo( KoPoint( x + m_width - rx, y - m_height ) ); + curveTo( KoPoint( x + m_width - rx * ( 1 - 0.552 ), y - m_height ), + KoPoint( x + m_width, y - m_height + ry * ( 1 - 0.552 ) ), + KoPoint( x + m_width, y - m_height + ry ) ); + if( ry < m_height / 2 ) + lineTo( KoPoint( x + m_width, y - ry ) ); + curveTo( KoPoint( x + m_width, y - ry * ( 1 - 0.552 ) ), + KoPoint( x + m_width - rx * ( 1 - 0.552 ), y ), + KoPoint( x + m_width - rx, y ) ); + if( rx < m_width / 2 ) + lineTo( KoPoint( x + rx, y ) ); + } + close(); +} + +QString +VRectangle::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Rectangle" ); +} + +void +VRectangle::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "RECT" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "x", m_topLeft.x() ); + me.setAttribute( "y", m_topLeft.y() ); + + me.setAttribute( "width", QString("%1pt").arg( m_width ) ); + me.setAttribute( "height", QString("%1pt").arg( m_height ) ); + + me.setAttribute( "rx", m_rx ); + me.setAttribute( "ry", m_ry ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VRectangle::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const +{ + // do not save deleted objects + if( state() == deleted ) + return; + + // different rx/ry is not supported by oasis, so act like it is a normal path + if( m_rx != 0. && m_ry != 0. && m_rx != m_ry ) + return VPath::saveOasis( store, docWriter, mainStyles, index ); + + docWriter->startElement( "draw:rect" ); + + //save all into pt + docWriter->addAttributePt( "svg:x", m_topLeft.x() ); + docWriter->addAttributePt( "svg:y", m_topLeft.y()-m_height ); + docWriter->addAttributePt( "svg:width", m_width ); + docWriter->addAttributePt( "svg:height", m_height ); + + if( m_rx != 0. && m_ry != 0. && m_rx == m_ry ) + docWriter->addAttributePt( "draw:corner-radius", m_rx ); + + VObject::saveOasis( store, docWriter, mainStyles, index ); + + QWMatrix tmpMat; + tmpMat.scale( 1, -1 ); + tmpMat.translate( 0, -document()->height() ); + + QString transform = buildOasisTransform( m_matrix*tmpMat ); + if( !transform.isEmpty() ) + docWriter->addAttribute( "draw:transform", transform ); + + docWriter->endElement(); +} + +bool +VRectangle::loadOasis( const QDomElement &element, KoOasisLoadingContext &context ) +{ + setState( normal ); + + m_width = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ), 10.0 ); + m_height = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ), 10.0 ); + + m_topLeft.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ) ); + m_topLeft.setY( m_height + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ) ); + + m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::draw, "corner-radius", QString::null ) ); + + init(); + + transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) ); + + QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null ); + if( !trafo.isEmpty() ) + transformOasis( trafo ); + + return VObject::loadOasis( element, context ); +} + +void +VRectangle::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_width = KoUnit::parseValue( element.attribute( "width" ), 10.0 ); + m_height = KoUnit::parseValue( element.attribute( "height" ), 10.0 ); + + m_topLeft.setX( KoUnit::parseValue( element.attribute( "x" ) ) ); + m_topLeft.setY( KoUnit::parseValue( element.attribute( "y" ) ) ); + + m_rx = KoUnit::parseValue( element.attribute( "rx" ) ); + m_ry = KoUnit::parseValue( element.attribute( "ry" ) ); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +VPath* +VRectangle::clone() const +{ + return new VRectangle( *this ); +} diff --git a/karbon/shapes/vrectangle.h b/karbon/shapes/vrectangle.h new file mode 100644 index 00000000..04bd20d0 --- /dev/null +++ b/karbon/shapes/vrectangle.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VRECTANGLE_H__ +#define __VRECTANGLE_H__ + +#include "vcomposite.h" +#include <koffice_export.h> + +class KARBONBASE_EXPORT VRectangle : public VPath +{ +public: + VRectangle( VObject* parent, VState state = edit ); + VRectangle( VObject* parent, + const KoPoint& topLeft, double width, double height, double rx = 0.0, double ry = 0.0 ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const; + virtual void load( const QDomElement& element ); + virtual bool loadOasis( const QDomElement &element, KoOasisLoadingContext &context ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + KoPoint m_topLeft; + double m_width; + double m_height; + double m_rx; + double m_ry; +}; + +#endif + diff --git a/karbon/shapes/vsinus.cc b/karbon/shapes/vsinus.cc new file mode 100644 index 00000000..a6c9ec4f --- /dev/null +++ b/karbon/shapes/vsinus.cc @@ -0,0 +1,206 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qwmatrix.h> + +#include "vglobal.h" +#include "vsinus.h" +#include "vtransformcmd.h" +#include <klocale.h> +#include <KoUnit.h> +#include <qdom.h> +#include <vdocument.h> + +VSinus::VSinus( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +VSinus::VSinus( VObject* parent, + const KoPoint& topLeft, double width, double height, uint periods ) + : VPath( parent ), m_topLeft( topLeft ), m_width( width), m_height( height ), m_periods( periods ) +{ + // We want at least 1 period: + if( m_periods < 1 ) + m_periods = 1; + init(); +} + +void +VSinus::init() +{ + KoPoint p1; + KoPoint p2; + KoPoint p3( 0.0, 0.0 ); + moveTo( p3 ); + + for ( uint i = 0; i < m_periods; ++i ) + { + p1.setX( i + 1.0/24.0 ); + p1.setY( ( 2.0 * VGlobal::sqrt2 - 1.0 ) * VGlobal::one_7 ); + p2.setX( i + 1.0/12.0 ); + p2.setY( ( 4.0 * VGlobal::sqrt2 - 2.0 ) * VGlobal::one_7 ); + p3.setX( i + 1.0/8.0 ); + p3.setY( VGlobal::sqrt2 * 0.5 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 1.0/6.0 ); + p1.setY( ( 3.0 * VGlobal::sqrt2 + 2.0 ) * VGlobal::one_7 ); + p2.setX( i + 5.0/24.0 ); + p2.setY( 1.0 ); + p3.setX( i + 1.0/4.0 ); + p3.setY( 1.0 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 7.0/24.0 ); + p1.setY( 1.0 ); + p2.setX( i + 1.0/3.0 ); + p2.setY( ( 3.0 * VGlobal::sqrt2 + 2.0 ) * VGlobal::one_7 ); + p3.setX( i + 3.0/8.0 ); + p3.setY( VGlobal::sqrt2 * 0.5 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 5.0/12.0 ); + p1.setY( ( 4.0 * VGlobal::sqrt2 - 2.0 ) * VGlobal::one_7 ); + p2.setX( i + 11.0/24.0 ); + p2.setY( ( 2.0 * VGlobal::sqrt2 - 1.0 ) * VGlobal::one_7 ); + p3.setX( i + 1.0/2.0 ); + p3.setY( 0.0 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 13.0/24.0 ); + p1.setY( -( 2.0 * VGlobal::sqrt2 - 1.0 ) * VGlobal::one_7 ); + p2.setX( i + 7.0/12.0 ); + p2.setY( -( 4.0 * VGlobal::sqrt2 - 2.0 ) * VGlobal::one_7 ); + p3.setX( i + 5.0/8.0 ); + p3.setY( -VGlobal::sqrt2 * 0.5 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 2.0/3.0 ); + p1.setY( -( 3.0 * VGlobal::sqrt2 + 2.0 ) * VGlobal::one_7 ); + p2.setX( i + 17.0/24.0 ); + p2.setY( -1.0 ); + p3.setX( i + 3.0/4.0 ); + p3.setY( -1.0 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 19.0/24.0 ); + p1.setY( -1.0 ); + p2.setX( i + 5.0/6.0 ); + p2.setY( -( 3.0 * VGlobal::sqrt2 + 2.0 ) * VGlobal::one_7 ); + p3.setX( i + 7.0/8.0 ); + p3.setY( -VGlobal::sqrt2 * 0.5 ); + curveTo( p1, p2, p3 ); + + p1.setX( i + 11.0/12.0 ); + p1.setY( -( 4.0 * VGlobal::sqrt2 - 2.0 ) * VGlobal::one_7 ); + p2.setX( i + 23.0/24.0 ); + p2.setY( -( 2.0 * VGlobal::sqrt2 - 1.0 ) * VGlobal::one_7 ); + p3.setX( i + 1.0 ); + p3.setY( 0.0 ); + curveTo( p1, p2, p3 ); + } + + // Translate and scale: + QWMatrix m; + m.translate( m_topLeft.x(), m_topLeft.y() - m_height * 0.5 ); + m.scale( m_width / m_periods, m_height * 0.5 ); + + // only tranform the path data + VTransformCmd cmd( 0L, m ); + cmd.VVisitor::visitVPath( *this ); + + m_matrix.reset(); +} + +QString +VSinus::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Sinus" ); +} + +void +VSinus::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "SINUS" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "x", m_topLeft.x() ); + me.setAttribute( "y", m_topLeft.y() ); + + me.setAttribute( "width", m_width ); + me.setAttribute( "height", m_height ); + + me.setAttribute( "periods", m_periods ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VSinus::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_width = KoUnit::parseValue( element.attribute( "width" ), 10.0 ); + m_height = KoUnit::parseValue( element.attribute( "height" ), 10.0 ); + + m_topLeft.setX( KoUnit::parseValue( element.attribute( "x" ) ) ); + m_topLeft.setY( KoUnit::parseValue( element.attribute( "y" ) ) ); + + m_periods = element.attribute( "periods" ).toUInt(); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +VPath* +VSinus::clone() const +{ + return new VSinus( *this ); +} + diff --git a/karbon/shapes/vsinus.h b/karbon/shapes/vsinus.h new file mode 100644 index 00000000..eb8d4f00 --- /dev/null +++ b/karbon/shapes/vsinus.h @@ -0,0 +1,51 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSINUS_H__ +#define __VSINUS_H__ + +#include "vcomposite.h" +#include <koffice_export.h> + +class KARBONBASE_EXPORT VSinus : public VPath +{ +public: + VSinus( VObject* parent, VState state = edit ); + VSinus( VObject* parent, + const KoPoint& topLeft, double width, double height, uint periods ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + KoPoint m_topLeft; + double m_width; + double m_height; + uint m_periods; +}; + +#endif + diff --git a/karbon/shapes/vspiral.cc b/karbon/shapes/vspiral.cc new file mode 100644 index 00000000..8f6d17c2 --- /dev/null +++ b/karbon/shapes/vspiral.cc @@ -0,0 +1,186 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <math.h> + +#include <qwmatrix.h> +#include <qdom.h> + +#include "vglobal.h" +#include "vspiral.h" +#include "vtransformcmd.h" +#include <klocale.h> +#include <KoUnit.h> +#include <vdocument.h> + +VSpiral::VSpiral( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +VSpiral::VSpiral( VObject* parent, + const KoPoint& center, double radius, uint segments, double fade, + bool clockwise, double angle, VSpiralType type ) + : VPath( parent ), m_center( center), m_radius( radius ), m_fade( fade ), m_segments( segments ), m_clockwise( clockwise ), m_angle( angle ), m_type( type ) +{ + init(); +} + +void +VSpiral::init() +{ + // It makes sense to have at least one segment: + if( m_segments < 1 ) + m_segments = 1; + + // Make sure the radius is positive: + if( m_radius < 0.0 ) + m_radius = -m_radius; + + // Fall back, when fade is out of range: + if( m_fade <= 0.0 || m_fade >= 1.0 ) + m_fade = 0.5; + + setFillRule( winding ); + + // advance by pi/2 clockwise or cclockwise? + double adv_ang = ( m_clockwise ? -1.0 : 1.0 ) * VGlobal::pi_2; + // radius of first segment is non-faded radius: + double r = m_radius; + + KoPoint oldP( 0.0, ( m_clockwise ? -1.0 : 1.0 ) * m_radius ); + KoPoint newP; + KoPoint newCenter( 0.0, 0.0 ); + moveTo( oldP ); + + for ( uint i = 0; i < m_segments; ++i ) + { + newP.setX( r * cos( adv_ang * ( i + 2 ) ) + newCenter.x() ); + newP.setY( r * sin( adv_ang * ( i + 2 ) ) + newCenter.y() ); + + if( m_type == round ) + arcTo( oldP + newP - newCenter, newP, r ); + else + lineTo( newP ); + + newCenter += ( newP - newCenter ) * ( 1.0 - m_fade ); + oldP = newP; + r *= m_fade; + } + + // translate path to center: + QWMatrix m; + m.translate( m_center.x(), m_center.y() ); + + // sadly it's not feasible to simply add angle while creation. + m.rotate( + ( m_angle + ( m_clockwise ? VGlobal::pi : 0.0 ) ) * // make cw-spiral start at mouse-pointer + VGlobal::one_pi_180 ); // one_pi_180 = 1/(pi/180) = 180/pi. + + // only tranform the path data + VTransformCmd cmd( 0L, m ); + cmd.VVisitor::visitVPath( *this ); + + m_matrix.reset(); +} + +QString +VSpiral::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Spiral" ); +} + +void +VSpiral::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "SPIRAL" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "cx", m_center.x() ); + me.setAttribute( "cy", m_center.y() ); + + me.setAttribute( "radius", m_radius ); + me.setAttribute( "angle", m_angle ); + me.setAttribute( "fade", m_fade ); + + me.setAttribute( "segments", m_segments ); + + me.setAttribute( "clockwise", m_clockwise ); + + me.setAttribute( "type", m_type ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VSpiral::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_radius = KoUnit::parseValue( element.attribute( "radius" ) ); + m_angle = element.attribute( "angle" ).toDouble(); + m_fade = element.attribute( "fade" ).toDouble(); + + m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) ); + m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) ); + + m_segments = element.attribute( "segments" ).toUInt(), + + m_clockwise = element.attribute( "clockwise" ).toInt(); + + m_type = (VSpiral::VSpiralType)element.attribute( "type" ).toInt(); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +VPath* +VSpiral::clone() const +{ + return new VSpiral( *this ); +} diff --git a/karbon/shapes/vspiral.h b/karbon/shapes/vspiral.h new file mode 100644 index 00000000..2b80f6ad --- /dev/null +++ b/karbon/shapes/vspiral.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSPIRAL_H__ +#define __VSPIRAL_H__ + +#include "vcomposite.h" +#include <koffice_export.h> + +class KARBONBASE_EXPORT VSpiral : public VPath +{ +public: + enum VSpiralType + { + round, + rectangular + }; + VSpiral( VObject* parent, VState state = edit ); + VSpiral( VObject* parent, + const KoPoint& center, double radius, uint segments, + double fade, bool clockwise, double angle = 0.0, VSpiralType type = round ); + + virtual QString name() const; + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + KoPoint m_center; + double m_radius; + double m_fade; + uint m_segments; + bool m_clockwise; + double m_angle; + VSpiralType m_type; +}; + +#endif + diff --git a/karbon/shapes/vstar.cc b/karbon/shapes/vstar.cc new file mode 100644 index 00000000..98391272 --- /dev/null +++ b/karbon/shapes/vstar.cc @@ -0,0 +1,348 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <math.h> + +#include <qwmatrix.h> +#include <qdom.h> + +#include "vglobal.h" +#include "vstar.h" +#include "vtransformcmd.h" +#include <klocale.h> +#include <KoUnit.h> +#include <vdocument.h> + +VStar::VStar( VObject* parent, VState state ) + : VPath( parent, state ) +{ +} + +VStar::VStar( VObject* parent, + const KoPoint& center, double outerRadius, double innerRadius, + uint edges, double angle, uint innerAngle, double roundness, VStarType type ) + : VPath( parent ), m_center( center), m_outerRadius( outerRadius ), m_innerRadius( innerRadius), m_edges( edges ), m_angle( angle ), m_innerAngle( innerAngle ), m_roundness( roundness ), m_type( type ) +{ + init(); +} + +void +VStar::init() +{ + double angle = m_angle; + + // A star should have at least 3 edges: + if( m_edges < 3 ) + m_edges = 3; + + // Make sure, radii are positive: + if( m_outerRadius < 0.0 ) + m_outerRadius = -m_outerRadius; + + if( m_innerRadius < 0.0 ) + m_innerRadius = -m_innerRadius; + + // trick for spoke, wheel (libart bug?) + if( m_type == spoke || m_type == wheel && m_roundness == 0.0 ) + m_roundness = 0.01; + + // We start at angle + VGlobal::pi_2: + KoPoint p2, p3; + KoPoint p( + m_outerRadius * cos( angle + VGlobal::pi_2 ), + m_outerRadius * sin( angle + VGlobal::pi_2 ) ); + moveTo( p ); + + double inAngle = VGlobal::twopi / 360 * m_innerAngle; + + if( m_type == star ) + { + int j = ( m_edges % 2 == 0 ) ? ( m_edges - 2 ) / 2 : ( m_edges - 1 ) / 2; + //innerRadius = getOptimalInnerRadius( outerRadius, edges, innerAngle ); + int jumpto = 0; + bool discontinueous = ( m_edges % 4 == 2 ); + + double outerRoundness = ( VGlobal::twopi * m_outerRadius * m_roundness ) / m_edges; + double nextOuterAngle; + + for ( uint i = 1; i < m_edges + 1; ++i ) + { + double nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( jumpto + 0.5 ); + p.setX( m_innerRadius * cos( nextInnerAngle ) ); + p.setY( m_innerRadius * sin( nextInnerAngle ) ); + if( m_roundness == 0.0 ) + lineTo( p ); + else + { + nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto; + p2.setX( m_outerRadius * cos( nextOuterAngle ) - + cos( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness ); + p2.setY( m_outerRadius * sin( nextOuterAngle ) - + sin( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness ); + + curveTo( p2, p, p ); + } + + jumpto = ( i * j ) % m_edges; + nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( jumpto - 0.5 ); + p.setX( m_innerRadius * cos( nextInnerAngle ) ); + p.setY( m_innerRadius * sin( nextInnerAngle ) ); + lineTo( p ); + + nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto; + p.setX( m_outerRadius * cos( nextOuterAngle ) ); + p.setY( m_outerRadius * sin( nextOuterAngle ) ); + + if( m_roundness == 0.0 ) + lineTo( p ); + else + { + p2.setX( m_innerRadius * cos( nextInnerAngle ) ); + p2.setY( m_innerRadius * sin( nextInnerAngle ) ); + + p3.setX( m_outerRadius * cos( nextOuterAngle ) + + cos( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness ); + p3.setY( m_outerRadius * sin( nextOuterAngle ) + + sin( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness ); + + curveTo( p2, p3, p ); + } + if( discontinueous && i == ( m_edges / 2 ) ) + { + angle += VGlobal::pi; + nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto; + p.setX( m_outerRadius * cos( nextOuterAngle ) ); + p.setY( m_outerRadius * sin( nextOuterAngle ) ); + moveTo( p ); + } + } + } + else + { + if( m_type == wheel || m_type == spoke ) + m_innerRadius = 0.0; + + double innerRoundness = ( VGlobal::twopi * m_innerRadius * m_roundness ) / m_edges; + double outerRoundness = ( VGlobal::twopi * m_outerRadius * m_roundness ) / m_edges; + + for ( uint i = 0; i < m_edges; ++i ) + { + double nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 1.0 ); + double nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 0.5 ); + if( m_type != polygon ) + { + p.setX( m_innerRadius * cos( nextInnerAngle ) ); + p.setY( m_innerRadius * sin( nextInnerAngle ) ); + + if( m_roundness == 0.0 ) + lineTo( p ); + else + { + p2.setX( m_outerRadius * + cos( angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i ) ) - + cos( angle + VGlobal::twopi / m_edges * ( i ) ) * outerRoundness ); + p2.setY( m_outerRadius * + sin( angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i ) ) - + sin( angle + VGlobal::twopi / m_edges * ( i ) ) * outerRoundness ); + + p3.setX( m_innerRadius * cos( nextInnerAngle ) + + cos( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness ); + p3.setY( m_innerRadius * sin( nextInnerAngle ) + + sin( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness ); + + if( m_type == gear ) + { + lineTo( p2 ); + lineTo( p3 ); + lineTo( p ); + } + else + curveTo( p2, p3, p ); + } + } + + p.setX( m_outerRadius * cos( nextOuterAngle ) ); + p.setY( m_outerRadius * sin( nextOuterAngle ) ); + + if( m_roundness == 0.0 ) + lineTo( p ); + else + { + p2.setX( m_innerRadius * cos( nextInnerAngle ) - + cos( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness ); + p2.setY( m_innerRadius * sin( nextInnerAngle ) - + sin( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness ); + + p3.setX( m_outerRadius * cos( nextOuterAngle ) + + cos( angle + VGlobal::twopi / m_edges * ( i + 1.0 ) ) * outerRoundness ); + p3.setY( m_outerRadius * sin( nextOuterAngle ) + + sin( angle + VGlobal::twopi / m_edges * ( i + 1.0 ) ) * outerRoundness ); + + if( m_type == gear ) + { + lineTo( p2 ); + lineTo( p3 ); + lineTo( p ); + } + else + curveTo( p2, p3, p ); + } + } + } + if( m_type == wheel || m_type == framed_star ) + { + close(); + for ( int i = m_edges - 1; i >= 0; --i ) + { + double nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 1.0 ); + p.setX( m_outerRadius * cos( nextOuterAngle ) ); + p.setY( m_outerRadius * sin( nextOuterAngle ) ); + lineTo( p ); + } + } + close(); + + // translate path to center: + QWMatrix m; + m.translate( m_center.x(), m_center.y() ); + + // only tranform the path data + VTransformCmd cmd( 0L, m ); + cmd.VVisitor::visitVPath( *this ); + + setFillRule( evenOdd ); + + m_matrix.reset(); +} + +double +VStar::getOptimalInnerRadius( uint edges, double outerRadius, uint /*innerAngle*/ ) +{ + int j = (edges % 2 == 0 ) ? ( edges - 2 ) / 2 : ( edges - 1 ) / 2; + + // get two well chosen lines of the star + KoPoint p1( outerRadius * cos( VGlobal::pi_2 ), outerRadius * sin( VGlobal::pi_2 ) ); + int jumpto = ( j ) % edges; + double nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges * jumpto; + KoPoint p2( outerRadius * cos( nextOuterAngle ), outerRadius * sin( nextOuterAngle ) ); + + nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges; + KoPoint p3( outerRadius * cos( nextOuterAngle ), + outerRadius * sin( nextOuterAngle ) ); + jumpto = ( edges - j + 1 ) % edges; + nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges * jumpto; + KoPoint p4( outerRadius * cos( nextOuterAngle ), outerRadius * sin( nextOuterAngle ) ); + + // calc (x, y) -> intersection point + double b1 = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() ); + double b2 = ( p4.y() - p3.y() ) / ( p4.x() - p3.x() ); + double a1 = p1.y() - b1 * p1.x(); + double a2 = p3.y() - b2 * p3.x(); + double x = -( a1 - a2 ) / ( b1 - b2 ); + double y = a1 + b1 * x; + // calc inner radius from intersection point and center + return sqrt( x * x + y * y ); +} + +QString +VStar::name() const +{ + QString result = VObject::name(); + return !result.isEmpty() ? result : i18n( "Star" ); +} + +void +VStar::save( QDomElement& element ) const +{ + VDocument *doc = document(); + if( doc && doc->saveAsPath() ) + { + VPath::save( element ); + return; + } + + if( state() != deleted ) + { + QDomElement me = element.ownerDocument().createElement( "STAR" ); + element.appendChild( me ); + + // save fill/stroke untransformed + VPath path( *this ); + VTransformCmd cmd( 0L, m_matrix.invert() ); + cmd.visit( path ); + path.VObject::save( me ); + //VObject::save( me ); + + me.setAttribute( "cx", m_center.x() ); + me.setAttribute( "cy", m_center.y() ); + + me.setAttribute( "outerradius", m_outerRadius ); + me.setAttribute( "innerradius", m_innerRadius ); + me.setAttribute( "edges", m_edges ); + + me.setAttribute( "angle", m_angle ); + me.setAttribute( "innerangle", m_innerAngle ); + + me.setAttribute( "roundness", m_roundness ); + + me.setAttribute( "type", m_type ); + + QString transform = buildSvgTransform(); + if( !transform.isEmpty() ) + me.setAttribute( "transform", transform ); + } +} + +void +VStar::load( const QDomElement& element ) +{ + setState( normal ); + + QDomNodeList list = element.childNodes(); + for( uint i = 0; i < list.count(); ++i ) + if( list.item( i ).isElement() ) + VObject::load( list.item( i ).toElement() ); + + m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) ); + m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) ); + + m_outerRadius = KoUnit::parseValue( element.attribute( "outerradius" ) ); + m_innerRadius = KoUnit::parseValue( element.attribute( "innerradius" ) ); + m_edges = element.attribute( "edges" ).toUInt(); + + m_innerAngle = element.attribute( "innerangle" ).toUInt(); + m_angle = element.attribute( "angle" ).toDouble(); + + m_roundness = element.attribute( "roundness" ).toDouble(); + + m_type =(VStar::VStarType) element.attribute( "type" ).toInt(); + + init(); + + QString trafo = element.attribute( "transform" ); + if( !trafo.isEmpty() ) + transform( trafo ); +} + +VPath* +VStar::clone() const +{ + return new VStar( *this ); +} diff --git a/karbon/shapes/vstar.h b/karbon/shapes/vstar.h new file mode 100644 index 00000000..7b7ec098 --- /dev/null +++ b/karbon/shapes/vstar.h @@ -0,0 +1,91 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTAR_H__ +#define __VSTAR_H__ + +#include "vcomposite.h" +#include <koffice_export.h> +/** + * This shape offers star-like shapes with a lot of parameters : + * + * Types : + * + * Star - fully connected star shape. + * Star outline - like star but without the cross connections. + * Framed star - like star outline but with an enclosing path. + * Spoke - basically a star outline with inner radius of zero. + * Wheel - like spoke but with enclosing path. + * Polygon - like VPolygon. + * Gear - variant on star outline, resembling the KDE gear. + * + * Parameters : + * + * Edges - number of edges, which must be greater or equal to 3. + * Outer radius - radius amount of circumcircle of the star. + * Inner radius - inner radius where star has to connect to. This value + * doesn't apply to polygon, spoke and wheel. + * Inner angle - extra radius amount for inner radius. + * Roundness - uses curves instead of lines for the star shape. + */ +class KARBONBASE_EXPORT VStar : public VPath +{ +public: + enum VStarType + { + star_outline, + spoke, + wheel, + polygon, + framed_star, + star, + gear + }; + VStar( VObject* parent, VState state = edit ); + VStar( VObject* parent, + const KoPoint& center, double outerRadius, double innerRadius, + uint edges, double angle = 0.0, uint innerAngle = 0, + double roundness = 0.0, VStarType type = star_outline ); + + static double getOptimalInnerRadius( uint edges, double outerRadius, uint innerAngle ); + + virtual QString name() const; + + + virtual void save( QDomElement& element ) const; + virtual void load( const QDomElement& element ); + + virtual VPath* clone() const; + +protected: + void init(); + +private: + KoPoint m_center; + double m_outerRadius; + double m_innerRadius; + uint m_edges; + double m_angle; + double m_innerAngle; + double m_roundness; + VStarType m_type; +}; + +#endif + diff --git a/karbon/templates/Makefile.am b/karbon/templates/Makefile.am new file mode 100644 index 00000000..8e915418 --- /dev/null +++ b/karbon/templates/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = basic diff --git a/karbon/templates/basic/.directory b/karbon/templates/basic/.directory new file mode 100644 index 00000000..9aa5ba11 --- /dev/null +++ b/karbon/templates/basic/.directory @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Basic +Name[bg]=Основни +Name[br]=Diazez +Name[ca]=Bàsic +Name[cy]=Sylfaenol +Name[da]=Basal +Name[de]=Basis +Name[el]=Βασικά +Name[eo]=Baza +Name[es]=Básico +Name[et]=Baasmallid +Name[fa]=پایهای +Name[fi]=Perus +Name[fr]=Basique +Name[fy]=Basis +Name[ga]=Bunúsach +Name[gl]=Básico +Name[he]=בסיס +Name[hi]=मूल +Name[hr]=Osnovno +Name[hu]=Alap +Name[is]=Einfalt +Name[it]=Semplice +Name[ja]=基本的 +Name[km]=គោល +Name[lv]=Pamata +Name[ms]=Asas +Name[nb]=Grunnleggende +Name[nds]=Eenfach +Name[ne]=आधारभूत +Name[nl]=Basis +Name[pl]=Podstawowy +Name[pt]=Básico +Name[pt_BR]=Básico +Name[ru]=Простой +Name[se]=Vuđolaš +Name[sk]=Základné +Name[sl]=Osnovno +Name[sr]=Основно +Name[sr@Latn]=Osnovno +Name[sv]=Grundläggande +Name[ta]=அடிப்படை +Name[tg]=Асосӣ +Name[tr]=Temel +Name[uk]=Простий +Name[uz]=Oddiy +Name[uz@cyrillic]=Оддий +Name[wa]=Di båze +Name[zh_CN]=基本 +Name[zh_TW]=基本 +X-KDE-DefaultTab=true diff --git a/karbon/templates/basic/Makefile.am b/karbon/templates/basic/Makefile.am new file mode 100644 index 00000000..d79a480e --- /dev/null +++ b/karbon/templates/basic/Makefile.am @@ -0,0 +1,9 @@ +templates_DATA = .directory empty.desktop +templatesdir = $(kde_datadir)/karbon/templates/Basic + +templatesrc_DATA = empty.karbon +templatesrcdir = $(kde_datadir)/karbon/templates/Basic/.source + +karbonicondir = $(kde_datadir)/karbon/icons +karbonicon_ICON = AUTO + diff --git a/karbon/templates/basic/cr48-action-template_empty.png b/karbon/templates/basic/cr48-action-template_empty.png Binary files differnew file mode 100644 index 00000000..d0d4d9b7 --- /dev/null +++ b/karbon/templates/basic/cr48-action-template_empty.png diff --git a/karbon/templates/basic/crsc-action-template_empty.svgz b/karbon/templates/basic/crsc-action-template_empty.svgz Binary files differnew file mode 100644 index 00000000..90ddf073 --- /dev/null +++ b/karbon/templates/basic/crsc-action-template_empty.svgz diff --git a/karbon/templates/basic/empty.desktop b/karbon/templates/basic/empty.desktop new file mode 100644 index 00000000..63191dbf --- /dev/null +++ b/karbon/templates/basic/empty.desktop @@ -0,0 +1,103 @@ +[Desktop Entry] +Type=Link +URL=.source/empty.karbon +Icon=template_empty +Name=Empty Document +Name[bg]=Празен документ +Name[br]=Teul goullo +Name[ca]=Document buit +Name[cs]=Prázdný dokument +Name[cy]=Dogfen Wag +Name[da]=Tomt dokument +Name[de]=Leeres Dokument +Name[el]=Κενό έγγραφο +Name[eo]=Malplena dokumento +Name[es]=Documento vacío +Name[et]=Tühi dokument +Name[eu]=Dokumentu hutsa +Name[fa]=سند خالی +Name[fi]=Tyhjä asiakirja +Name[fr]=Document vide +Name[fy]=Leech dokumint +Name[ga]=Cáipéis Fholamh +Name[gl]=Documento Valeiro +Name[he]=מסמך ריק +Name[hi]=रिक्त दस्तावेज़ +Name[hr]=Prazan dokument +Name[hu]=Üres dokumentum +Name[is]=Tómt skjal +Name[it]=Documento vuoto +Name[ja]=空のドキュメント +Name[km]=ឯកសារទទេ +Name[lt]=Tuščias dokumentas +Name[lv]=Tukšs dokuments +Name[ms]=Dokumen Kosong +Name[nb]=Tomt dokument +Name[nds]=Leddig Dokment +Name[ne]=खाली कागजात +Name[nl]=Leeg Document +Name[nn]=Tomt dokument +Name[pl]=Pusty dokument +Name[pt]=Documento Vazio +Name[pt_BR]=Documento Vazio +Name[ru]=Пустой документ +Name[se]=Guorus dokumeanta +Name[sk]=Prázdny dokument +Name[sl]=Prazen dokument +Name[sr]=Празан документ +Name[sr@Latn]=Prazan dokument +Name[sv]=Tomt dokument +Name[ta]=காலி ஆவணம் +Name[tg]=Ҳуҷҷати Холӣ +Name[tr]=Boş Belge +Name[uk]=Порожній документ +Name[uz]=Boʻsh hujjat +Name[uz@cyrillic]=Бўш ҳужжат +Name[wa]=Documint vude +Name[zh_CN]=空文档 +Name[zh_TW]=空白文件 +Comment=Creates an empty document +Comment[bg]=Създаване на празен документ +Comment[br]=Krouiñ un teul goullo +Comment[ca]=Crea un document buit +Comment[cy]=Creuir dogfen wag +Comment[da]=Opretter et tomt dokument +Comment[de]=Erstellt ein leeres Dokument +Comment[el]=Δημιουργεί ένα κενό έγγραφο +Comment[eo]=Kreas malplenan dokumenton +Comment[es]=Crea un documento vacío +Comment[et]=Tühja dokumendi loomine +Comment[fa]=یک سند خالی ایجاد میکند. +Comment[fi]=Luo tyhjän asiakirja +Comment[fr]=Crée un document vide +Comment[fy]=Een leech dokumint oanmeitsje +Comment[ga]=Cruthaigh cáipéis fholamh +Comment[gl]=Cría un documento valeiro +Comment[he]=יוצר מסמך ריק +Comment[hr]=Izrada praznog dokumenta +Comment[hu]=Létrehoz egy üres dokumentumot +Comment[is]=Býr til tómt skjal +Comment[it]=Crea un documento vuoto +Comment[ja]=空のドキュメントを作成 +Comment[km]=បង្កើតឯកសារទទេមួយ +Comment[lt]=Sukuria tuščią dokumentą +Comment[lv]=Izveido tukšu dokumentu +Comment[nb]=Lager et tomt dokument +Comment[nds]=Stellt en leddig Dokment op +Comment[ne]=एउटा खाली कागजात सिर्जना गर्दछ +Comment[nl]=Een leeg document aanmaken +Comment[pl]=Tworzy pusty dokument +Comment[pt]=Cria um documento vazio +Comment[pt_BR]=Cria um documento vazio +Comment[ru]=Создать пустой документ +Comment[se]=Ráhkada guorus dokumeantta +Comment[sk]=Vytvorí prázdny dokument +Comment[sl]=Ustvari prazen dokument +Comment[sr]=Прави празан документ +Comment[sr@Latn]=Pravi prazan dokument +Comment[sv]=Skapar ett tomt dokument +Comment[uk]=Створює порожній документ +Comment[uz]=Boʻsh hujjatni yaratish +Comment[uz@cyrillic]=Бўш ҳужжатни яратиш +Comment[zh_CN]=创建一个空文档 +Comment[zh_TW]=建立空白文件 diff --git a/karbon/templates/basic/empty.karbon b/karbon/templates/basic/empty.karbon Binary files differnew file mode 100644 index 00000000..7cde1121 --- /dev/null +++ b/karbon/templates/basic/empty.karbon diff --git a/karbon/tests/14.karbon b/karbon/tests/14.karbon Binary files differnew file mode 100644 index 00000000..c790e3e8 --- /dev/null +++ b/karbon/tests/14.karbon diff --git a/karbon/tests/README b/karbon/tests/README new file mode 100644 index 00000000..bd3d070c --- /dev/null +++ b/karbon/tests/README @@ -0,0 +1 @@ +Use "cvs add -kb" to add binaries. Or otherwise werner will shoot you. diff --git a/karbon/tests/combined.karbon b/karbon/tests/combined.karbon Binary files differnew file mode 100644 index 00000000..545ea162 --- /dev/null +++ b/karbon/tests/combined.karbon diff --git a/karbon/tests/dash.karbon b/karbon/tests/dash.karbon Binary files differnew file mode 100644 index 00000000..f487d211 --- /dev/null +++ b/karbon/tests/dash.karbon diff --git a/karbon/tests/grad.karbon b/karbon/tests/grad.karbon Binary files differnew file mode 100644 index 00000000..75b26fde --- /dev/null +++ b/karbon/tests/grad.karbon diff --git a/karbon/tests/oasis-karbon.sh b/karbon/tests/oasis-karbon.sh new file mode 100755 index 00000000..60ec6f54 --- /dev/null +++ b/karbon/tests/oasis-karbon.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# This script helps finding out problems in the OASIS loading/saving code, +# by converting .karbon -> .odg -> .karbon and comparing the initial and final .karbon files. +# We use the karbon format as a "dump" of the Karbon data, to check if everything is correct +# in memory, but the point is of course to ensure that the .odg has all the information. + +# To use this script, you need to pass the full path to an existing karbon file as argument. +# Don't use a relative path, dcopstart won't handle it +input="$1" + +# Set this to 1 in order to validate the saved oasis document using oasislint +checkoasis="1" + +appname=karbon +oldextension=karbon +oasisextension=odg +oasismimetype=application/vnd.oasis.opendocument.graphics + +test -f "$input" || { echo "No such file $input"; exit 1; } + +# Load old native file +appid=`dcopstart $appname $input` +test -n "$appid" || { echo "Error starting $appname!"; exit 1; } +while `dcop $appid Document-0 isLoading` == "true"; do + sleep 1; +done + +# Save again (in case of changes in syntax etc.) +origfile=$PWD/oasisregtest-initial.$oldextension +dcop $appid Document-0 saveAs $origfile || exit 1 +test -f $origfile || exit 1 + +# Save to OASIS +tmpoasisfile=$PWD/oasisregtest.$oasisextension +dcop $appid Document-0 setOutputMimeType $oasismimetype || exit 1 +dcop $appid Document-0 saveAs $tmpoasisfile || exit 1 +test -f $tmpoasisfile || exit 1 + +dcopquit $appid + +# Load resulting OASIS file, convert to old native format +tmpnativefile=$PWD/oasisregtest-final.$oldextension +appid=`dcopstart $appname $tmpoasisfile` +while `dcop $appid Document-0 isLoading` == "true"; do + sleep 1; +done +dcop $appid Document-0 setOutputMimeType "application/x-$appname" || exit 1 +dcop $appid Document-0 saveAs $tmpnativefile || exit 1 +test -f $tmpnativefile || exit 1 + +# Unpack everything +rm -rf oasisregtest-orig +mkdir oasisregtest-orig +rm -rf oasisregtest-final +mkdir oasisregtest-final +rm -rf oasisregtest-oasis +mkdir oasisregtest-oasis +cd oasisregtest-orig || exit 1 +unzip $origfile || exit 1 +cd .. +cd oasisregtest-final || exit 1 +unzip $tmpnativefile || exit 1 +cd .. +# Validate OASIS format +cd oasisregtest-oasis || exit 1 +unzip $tmpoasisfile || exit 1 +if test "$checkoasis" = "1"; then + if type -p oasislint >/dev/null 2>&1; then + for f in content.xml styles.xml meta.xml settings.xml; do + echo "Checking $f..." ; oasislint $f + done + fi + if type -p oasislint-strict >/dev/null 2>&1; then + for f in content.xml styles.xml meta.xml settings.xml; do + echo "Checking $f strict..." && oasislint-strict $f + done + fi +fi +cd .. + +# Compare initial and final "native format" files +diff -urp oasisregtest-orig oasisregtest-final 2>&1 | tee oasisdiff | less + +echo "See oasisregtest-oasis for the OASIS xml files." +echo "For a better diffing mechanism, launch xemacs and paste into a terminal:" +echo "gnudoit '(ediff-files \"$PWD/oasisregtest-orig/maindoc.xml\" \"$PWD/oasisregtest-final/maindoc.xml\")'" diff --git a/karbon/tests/opacity.karbon b/karbon/tests/opacity.karbon Binary files differnew file mode 100644 index 00000000..e20f6f6d --- /dev/null +++ b/karbon/tests/opacity.karbon diff --git a/karbon/tests/pat.karbon b/karbon/tests/pat.karbon Binary files differnew file mode 100644 index 00000000..1a968a2a --- /dev/null +++ b/karbon/tests/pat.karbon diff --git a/karbon/tests/polyline.karbon b/karbon/tests/polyline.karbon Binary files differnew file mode 100644 index 00000000..9f9365df --- /dev/null +++ b/karbon/tests/polyline.karbon diff --git a/karbon/tests/stroke.karbon b/karbon/tests/stroke.karbon Binary files differnew file mode 100644 index 00000000..118f8b5d --- /dev/null +++ b/karbon/tests/stroke.karbon diff --git a/karbon/tests/trasparency.karbon b/karbon/tests/trasparency.karbon Binary files differnew file mode 100644 index 00000000..4c45f1e2 --- /dev/null +++ b/karbon/tests/trasparency.karbon diff --git a/karbon/tools/Makefile.am b/karbon/tools/Makefile.am new file mode 100644 index 00000000..71ba99b8 --- /dev/null +++ b/karbon/tools/Makefile.am @@ -0,0 +1,63 @@ +kde_services_DATA = karbondefaulttools.desktop + +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../commands \ + -I$(srcdir)/../core \ + -I$(srcdir)/../dialogs \ + -I$(srcdir)/../widgets \ + -I$(srcdir)/../dockers \ + -I$(srcdir)/../render \ + -I$(srcdir)/../shapes \ + -I$(srcdir)/../visitors \ + $(all_includes) + +kde_module_LTLIBRARIES = karbon_defaulttools.la + +noinst_HEADERS = \ + vcurvefit.h \ + vrotatetool.h \ + vselectnodestool.h \ + vselecttool.h \ + vsheartool.h \ + vellipsetool.h \ + vgradienttool.h \ + vpatterntool.h \ + vpenciltool.h \ + vpolygontool.h \ + vpolylinetool.h \ + vrectangletool.h \ + vroundrecttool.h \ + vshapetool.h \ + vsinustool.h \ + vspiraltool.h \ + vstartool.h \ + vtexttool.h \ + vdefaulttools.h + +karbon_defaulttools_la_SOURCES = \ + vcurvefit.cc \ + vrotatetool.cc \ + vselectnodestool.cc \ + vselecttool.cc \ + vsheartool.cc \ + vellipsetool.cc \ + vgradienttool.cc \ + vpatterntool.cc \ + vpenciltool.cc \ + vpolygontool.cc \ + vpolylinetool.cc \ + vrectangletool.cc \ + vroundrecttool.cc \ + vshapetool.cc \ + vsinustool.cc \ + vspiraltool.cc \ + vstartool.cc \ + vtexttool.cc \ + vdefaulttools.cc + +karbon_defaulttools_la_LIBADD = $(LIB_KPARTS) $(LIB_KOFFICEUI) ../libkarboncommon.la +karbon_defaulttools_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +karbon_defaulttools_la_METASOURCES = \ + AUTO diff --git a/karbon/tools/gradienttoolplugin.rc b/karbon/tools/gradienttoolplugin.rc new file mode 100644 index 00000000..ba3746e9 --- /dev/null +++ b/karbon/tools/gradienttoolplugin.rc @@ -0,0 +1,3 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="gradienttoolplugin" library="karbon_gradienttoolplugin"> +</kpartplugin> diff --git a/karbon/tools/karbondefaulttools.desktop b/karbon/tools/karbondefaulttools.desktop new file mode 100644 index 00000000..193c5d6c --- /dev/null +++ b/karbon/tools/karbondefaulttools.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Name=Default Tools +Name[bg]=Инструменти по подразбиране +Name[br]=Ostilhoù dre ziouer +Name[ca]=Eines per defecte +Name[cy]=Offer Rhagosodol +Name[da]=Standardværktøjer +Name[de]=Standardwerkzeuge +Name[el]=Προκαθορισμένα εργαλεία +Name[eo]=Aprioraj Iloj +Name[es]=Herramientas predefinidas +Name[et]=Vaiketööriistad +Name[eu]=Tresna lehenetsiak +Name[fa]=ابزارهای پیشفرض +Name[fi]=Oletustyökalut +Name[fr]=Outils par défaut +Name[fy]=Standert ark +Name[ga]=Uirlisí Réamhshocraithe +Name[gl]=Ferramentas Predefinidas +Name[he]=כלים המוגדרים כברירת מחדל +Name[hi]=डिफ़ॉल्ट औज़ार +Name[hr]=Zadani alati +Name[hu]=Alapértelmezett eszközök +Name[is]=Sjálfgefin tól +Name[it]=Strumenti predefiniti +Name[ja]=標準ツール +Name[km]=ឧបករណ៍លំនាំដើម +Name[lt]=Numatyti įrankiai +Name[lv]=Noklusējuma rīks +Name[ms]=Alat Piawai +Name[nb]=Standardverktøy +Name[nds]=Standardwarktüüch +Name[ne]=पूर्वनिर्धारित उपकरणहरू +Name[nl]=Standaardgereedschappen +Name[nn]=Standardverktøy +Name[pl]=Domyślne narzędzia +Name[pt]=Ferramentas Predefinidas +Name[pt_BR]=Ferramentas Padrão +Name[ru]=Стандартный инструментарий +Name[se]=Standárdreaiddut +Name[sk]=Štandardné nástroje +Name[sl]=Privzeta orodja +Name[sr]=Подразумевани алати +Name[sr@Latn]=Podrazumevani alati +Name[sv]=Standardverktyg +Name[ta]=முன்னிருப்பு கருவிகள் +Name[tr]=Öntanımlı Araçlar +Name[uk]=Типові інструменти +Name[uz]=Andoza vositalar +Name[uz@cyrillic]=Андоза воситалар +Name[zh_CN]=默认工具 +Name[zh_TW]=預設工具 +ServiceTypes=Karbon/CoreModule +Type=Service +X-KDE-Library=karbon_defaulttools diff --git a/karbon/tools/patterntoolplugin.rc b/karbon/tools/patterntoolplugin.rc new file mode 100644 index 00000000..b1019eab --- /dev/null +++ b/karbon/tools/patterntoolplugin.rc @@ -0,0 +1,3 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="patterntoolplugin" library="karbon_patterntoolplugin"> +</kpartplugin> diff --git a/karbon/tools/vcurvefit.cc b/karbon/tools/vcurvefit.cc new file mode 100644 index 00000000..08dbda44 --- /dev/null +++ b/karbon/tools/vcurvefit.cc @@ -0,0 +1,565 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <karbon_part.h> +#include <karbon_view.h> +#include <core/vcolor.h> +#include <core/vcomposite.h> +#include <core/vfill.h> +#include <core/vstroke.h> +#include <core/vglobal.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <commands/vshapecmd.h> + +/* + An Algorithm for Automatically Fitting Digitized Curves + by Philip J. Schneider + from "Graphics Gems", Academic Press, 1990 + + http://www.acm.org/pubs/tog/GraphicsGems/gems/FitCurves.c + http://www.acm.org/pubs/tog/GraphicsGems/gems/README +*/ + + +#include "vcurvefit.h" + +#define MAXPOINTS 1000 /* The most points you can have */ + + +class FitVector { + public: + FitVector(KoPoint &p){ + m_X=p.x(); + m_Y=p.y(); + } + + FitVector(){ + m_X=0; + m_Y=0; + } + + FitVector(KoPoint &a,KoPoint &b){ + m_X=a.x()-b.x(); + m_Y=a.y()-b.y(); + } + + void normalize(){ + double len=length(); + if(len==0.0f) + return; + m_X/=len; m_Y/=len; + } + + void negate(){ + m_X = -m_X; + m_Y = -m_Y; + } + + void scale(double s){ + double len = length(); + if(len==0.0f) + return; + m_X *= s/len; + m_Y *= s/len; + } + + double dot(FitVector &v){ + return ((m_X*v.m_X)+(m_Y*v.m_Y)); + } + + double length(){ + return (double) sqrt(m_X*m_X+m_Y*m_Y); + } + + KoPoint operator+(KoPoint &p){ + KoPoint b(p.x()+m_X,p.y()+m_Y); + return b; + } + + public: + double m_X,m_Y; +}; + +double distance(KoPoint *p1,KoPoint *p2){ + double dx = (p1->x()-p2->x()); + double dy = (p1->y()-p2->y()); + return sqrt( dx*dx + dy*dy ); +} + + +FitVector ComputeLeftTangent(QPtrList<KoPoint> &points,int end){ + FitVector tHat1(*points.at(end+1),*points.at(end)); + + tHat1.normalize(); + + return tHat1; +} + +FitVector ComputeRightTangent(QPtrList<KoPoint> &points,int end){ + FitVector tHat1(*points.at(end-1),*points.at(end)); + + tHat1.normalize(); + + return tHat1; +} + +/* + * ChordLengthParameterize : + * Assign parameter values to digitized points + * using relative distances between points. + */ +static double *ChordLengthParameterize(QPtrList<KoPoint> points,int first,int last) +{ + int i; + double *u; /* Parameterization */ + + u = new double[(last-first+1)]; + + u[0] = 0.0; + for (i = first+1; i <= last; i++) { + u[i-first] = u[i-first-1] + + distance(points.at(i), points.at(i-1)); + } + + for (i = first + 1; i <= last; i++) { + u[i-first] = u[i-first] / u[last-first]; + } + + return(u); +} + +static FitVector VectorAdd(FitVector a,FitVector b) +{ + FitVector c; + c.m_X = a.m_X + b.m_X; c.m_Y = a.m_Y + b.m_Y; + return (c); +} +static FitVector VectorScale(FitVector v,double s) +{ + FitVector result; + result.m_X = v.m_X * s; result.m_Y = v.m_Y * s; + return (result); +} + +static FitVector VectorSub(FitVector a,FitVector b) +{ + FitVector c; + c.m_X = a.m_X - b.m_X; c.m_Y = a.m_Y - b.m_Y; + return (c); +} + +static FitVector ComputeCenterTangent(QPtrList<KoPoint> points,int center) +{ + FitVector V1, V2, tHatCenter; + + FitVector cpointb = *points.at(center-1); + FitVector cpoint = *points.at(center); + FitVector cpointa = *points.at(center+1); + + V1 = VectorSub(cpointb,cpoint); + V2 = VectorSub(cpoint,cpointa); + tHatCenter.m_X= ((V1.m_X + V2.m_X)/2.0); + tHatCenter.m_Y= ((V1.m_Y + V2.m_Y)/2.0); + tHatCenter.normalize(); + return tHatCenter; +} + +/* + * B0, B1, B2, B3 : + * Bezier multipliers + */ +static double B0(double u) +{ + double tmp = 1.0 - u; + return (tmp * tmp * tmp); +} + + +static double B1(double u) +{ + double tmp = 1.0 - u; + return (3 * u * (tmp * tmp)); +} + +static double B2(double u) +{ + double tmp = 1.0 - u; + return (3 * u * u * tmp); +} + +static double B3(double u) +{ + return (u * u * u); +} + +/* + * GenerateBezier : + * Use least-squares method to find Bezier control points for region. + * + */ +KoPoint* GenerateBezier(QPtrList<KoPoint> &points, int first, int last, double *uPrime,FitVector tHat1,FitVector tHat2) +{ + int i; + FitVector A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ + int nPts; /* Number of pts in sub-curve */ + double C[2][2]; /* Matrix C */ + double X[2]; /* Matrix X */ + double det_C0_C1, /* Determinants of matrices */ + det_C0_X, + det_X_C1; + double alpha_l, /* Alpha values, left and right */ + alpha_r; + FitVector tmp; /* Utility variable */ + KoPoint *curve; + + curve = new KoPoint[4]; + nPts = last - first + 1; + + + /* Compute the A's */ + for (i = 0; i < nPts; i++) { + FitVector v1, v2; + v1 = tHat1; + v2 = tHat2; + v1.scale(B1(uPrime[i])); + v2.scale(B2(uPrime[i])); + A[i][0] = v1; + A[i][1] = v2; + } + + /* Create the C and X matrices */ + C[0][0] = 0.0; + C[0][1] = 0.0; + C[1][0] = 0.0; + C[1][1] = 0.0; + X[0] = 0.0; + X[1] = 0.0; + + for (i = 0; i < nPts; i++) { + C[0][0] += (A[i][0]).dot(A[i][0]); + C[0][1] += A[i][0].dot(A[i][1]); + /* C[1][0] += V2Dot(&A[i][0], &A[i][1]);*/ + C[1][0] = C[0][1]; + C[1][1] += A[i][1].dot(A[i][1]); + + FitVector vfirstp1(*points.at(first+i)); + FitVector vfirst(*points.at(first)); + FitVector vlast(*points.at(last)); + + tmp = VectorSub(vfirstp1, + VectorAdd( + VectorScale(vfirst, B0(uPrime[i])), + VectorAdd( + VectorScale(vfirst, B1(uPrime[i])), + VectorAdd( + VectorScale(vlast, B2(uPrime[i])), + VectorScale(vlast, B3(uPrime[i])) )))); + + + X[0] += A[i][0].dot(tmp); + X[1] += A[i][1].dot(tmp); + } + + /* Compute the determinants of C and X */ + det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; + det_C0_X = C[0][0] * X[1] - C[0][1] * X[0]; + det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; + + /* Finally, derive alpha values */ + if (det_C0_C1 == 0.0) { + det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12; + } + alpha_l = det_X_C1 / det_C0_C1; + alpha_r = det_C0_X / det_C0_C1; + + + /* If alpha negative, use the Wu/Barsky heuristic (see text) */ + /* (if alpha is 0, you get coincident control points that lead to + * divide by zero in any subsequent NewtonRaphsonRootFind() call. */ + if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) { + double dist = distance(points.at(last),points.at(first)) / + 3.0; + + curve[0] = *points.at(first); + curve[3] = *points.at(last); + + tHat1.scale(dist); + tHat2.scale(dist); + + curve[1] = tHat1 + curve[0]; + curve[2] = tHat2 + curve[3]; + return curve; + } + + /* First and last control points of the Bezier curve are */ + /* positioned exactly at the first and last data points */ + /* Control points 1 and 2 are positioned an alpha distance out */ + /* on the tangent vectors, left and right, respectively */ + curve[0] = *points.at(first); + curve[3] = *points.at(last); + + tHat1.scale(alpha_l); + tHat2.scale(alpha_r); + + curve[1] = tHat1 + curve[0]; + curve[2] = tHat2 + curve[3]; + + return (curve); +} + +/* + * Bezier : + * Evaluate a Bezier curve at a particular parameter value + * + */ +static KoPoint BezierII(int degree,KoPoint *V, double t) +{ + int i, j; + KoPoint Q; /* Point on curve at parameter t */ + KoPoint *Vtemp; /* Local copy of control points */ + + Vtemp = new KoPoint[degree+1]; + + for (i = 0; i <= degree; i++) { + Vtemp[i] = V[i]; + } + + /* Triangle computation */ + for (i = 1; i <= degree; i++) { + for (j = 0; j <= degree-i; j++) { + Vtemp[j].setX((1.0 - t) * Vtemp[j].x() + t * Vtemp[j+1].x()); + Vtemp[j].setY((1.0 - t) * Vtemp[j].y() + t * Vtemp[j+1].y()); + } + } + + Q = Vtemp[0]; + delete[] Vtemp; + return Q; +} + +/* + * ComputeMaxError : + * Find the maximum squared distance of digitized points + * to fitted curve. +*/ +static double ComputeMaxError(QPtrList<KoPoint> points,int first,int last,KoPoint *curve,double *u,int *splitPoint) +{ + int i; + double maxDist; /* Maximum error */ + double dist; /* Current error */ + KoPoint P; /* Point on curve */ + FitVector v; /* Vector from point to curve */ + + *splitPoint = (last - first + 1)/2; + maxDist = 0.0; + for (i = first + 1; i < last; i++) { + P = BezierII(3, curve, u[i-first]); + v = VectorSub(P, *points.at(i)); + dist = v.length(); + if (dist >= maxDist) { + maxDist = dist; + *splitPoint = i; + } + } + return (maxDist); +} + + +/* + * NewtonRaphsonRootFind : + * Use Newton-Raphson iteration to find better root. + */ +static double NewtonRaphsonRootFind(KoPoint *Q,KoPoint P,double u) +{ + double numerator, denominator; + KoPoint Q1[3], Q2[2]; /* Q' and Q'' */ + KoPoint Q_u, Q1_u, Q2_u; /*u evaluated at Q, Q', & Q'' */ + double uPrime; /* Improved u */ + int i; + + /* Compute Q(u) */ + Q_u = BezierII(3,Q, u); + + /* Generate control vertices for Q' */ + for (i = 0; i <= 2; i++) { + Q1[i].setX((Q[i+1].x() - Q[i].x()) * 3.0); + Q1[i].setY((Q[i+1].y() - Q[i].y()) * 3.0); + } + + /* Generate control vertices for Q'' */ + for (i = 0; i <= 1; i++) { + Q2[i].setX((Q1[i+1].x() - Q1[i].x()) * 2.0); + Q2[i].setY((Q1[i+1].y() - Q1[i].y()) * 2.0); + } + + /* Compute Q'(u) and Q''(u) */ + Q1_u = BezierII(2, Q1, u); + Q2_u = BezierII(1, Q2, u); + + /* Compute f(u)/f'(u) */ + numerator = (Q_u.x() - P.x()) * (Q1_u.x()) + (Q_u.y() - P.y()) * (Q1_u.y()); + denominator = (Q1_u.x()) * (Q1_u.x()) + (Q1_u.y()) * (Q1_u.y()) + + (Q_u.x() - P.x()) * (Q2_u.x()) + (Q_u.y() - P.y()) * (Q2_u.y()); + + /* u = u - f(u)/f'(u) */ + uPrime = u - (numerator/denominator); + return (uPrime); +} + +/* + * Reparameterize: + * Given set of points and their parameterization, try to find + * a better parameterization. + * + */ +static double *Reparameterize(QPtrList<KoPoint> points,int first,int last,double *u,KoPoint *curve) +{ + int nPts = last-first+1; + int i; + double *uPrime; /* New parameter values */ + + uPrime = new double[nPts]; + for (i = first; i <= last; i++) { + uPrime[i-first] = NewtonRaphsonRootFind(curve, *points.at(i), u[i- + first]); + } + return (uPrime); +} + +KoPoint *FitCubic(QPtrList<KoPoint> &points,int first,int last,FitVector tHat1,FitVector tHat2,float error,int &width){ + double *u; + double *uPrime; + double maxError; + int splitPoint; + int nPts; + double iterationError; + int maxIterations=4; + FitVector tHatCenter; + KoPoint *curve; + int i; + + width=0; + + + iterationError=error*error; + nPts = last-first+1; + + if(nPts == 2){ + double dist = distance(points.at(last), points.at(first)) / 3.0; + + curve = new KoPoint[4]; + + curve[0] = *points.at(first); + curve[3] = *points.at(last); + + tHat1.scale(dist); + tHat2.scale(dist); + + curve[1] = tHat1 + curve[0]; + curve[2] = tHat2 + curve[3]; + + width=4; + return curve; + } + + /* Parameterize points, and attempt to fit curve */ + u = ChordLengthParameterize(points, first, last); + curve = GenerateBezier(points, first, last, u, tHat1, tHat2); + + + /* Find max deviation of points to fitted curve */ + maxError = ComputeMaxError(points, first, last, curve, u, &splitPoint); + if (maxError < error) { + delete[] u; + width=4; + return curve; + } + + + /* If error not too large, try some reparameterization */ + /* and iteration */ + if (maxError < iterationError) { + for (i = 0; i < maxIterations; i++) { + uPrime = Reparameterize(points, first, last, u, curve); + curve = GenerateBezier(points, first, last, uPrime, tHat1, tHat2); + maxError = ComputeMaxError(points, first, last, + curve, uPrime, &splitPoint); + if (maxError < error) { + delete[] u; + width=4; + return curve; + } + delete[] u; + u = uPrime; + } + } + + /* Fitting failed -- split at max error point and fit recursively */ + delete[] u; + delete[] curve; + tHatCenter = ComputeCenterTangent(points, splitPoint); + + int w1,w2; + KoPoint *cu1=NULL, *cu2=NULL; + cu1 = FitCubic(points, first, splitPoint, tHat1, tHatCenter, error,w1); + + tHatCenter.negate(); + cu2 = FitCubic(points, splitPoint, last, tHatCenter, tHat2, error,w2); + + KoPoint *newcurve = new KoPoint[w1+w2]; + for(int i=0;i<w1;i++){ + newcurve[i]=cu1[i]; + } + for(int i=0;i<w2;i++){ + newcurve[i+w1]=cu2[i]; + } + + delete[] cu1; + delete[] cu2; + width=w1+w2; + return newcurve; +} + + +VPath *bezierFit(QPtrList<KoPoint> &points,float error){ + FitVector tHat1, tHat2; + + tHat1 = ComputeLeftTangent(points,0); + tHat2 = ComputeRightTangent(points,points.count()-1); + + int width=0; + KoPoint *curve; + curve = FitCubic(points,0,points.count()-1,tHat1,tHat2,error,width); + + VPath *path = new VPath(NULL); + + if(width>3){ + path->moveTo(curve[0]); + path->curveTo(curve[1],curve[2],curve[3]); + for(int i=4;i<width;i+=4){ + path->curveTo(curve[i+1],curve[i+2],curve[i+3]); + } + } + + + delete[] curve; + return path; +} + diff --git a/karbon/tools/vcurvefit.h b/karbon/tools/vcurvefit.h new file mode 100644 index 00000000..b9e54d1d --- /dev/null +++ b/karbon/tools/vcurvefit.h @@ -0,0 +1,11 @@ +#ifndef __VCURVEFIT_H__ +#define __VCURVEFIT_H__ + +#include <qstring.h> +#include <qptrlist.h> +#include "KoPoint.h" + +VPath *bezierFit(QPtrList<KoPoint> &points,float error); + +#endif + diff --git a/karbon/tools/vdefaulttools.cc b/karbon/tools/vdefaulttools.cc new file mode 100644 index 00000000..c3a713ec --- /dev/null +++ b/karbon/tools/vdefaulttools.cc @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <kgenericfactory.h> + +#include "karbon_factory.h" +#include "karbon_tool_factory.h" +#include "karbon_tool_registry.h" + +#include "vdefaulttools.h" + +#include "vellipsetool.h" +#include "vgradienttool.h" +#include "vpatterntool.h" +#include "vpenciltool.h" +#include "vpolygontool.h" +#include "vpolylinetool.h" +#include "vrectangletool.h" +#include "vrotatetool.h" +#include "vroundrecttool.h" +#include "vselectnodestool.h" +#include "vselecttool.h" +#include "vshapetool.h" +#include "vsheartool.h" +#include "vsinustool.h" +#include "vspiraltool.h" +#include "vstartool.h" +#include "vtexttool.h" + +typedef KGenericFactory<VDefaultTools> VDefaultToolsFactory; +K_EXPORT_COMPONENT_FACTORY( karbon_defaulttools, VDefaultToolsFactory( "karbon_defaulttools" ) ) + +VDefaultTools::VDefaultTools(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(VDefaultToolsFactory::instance()); + + kdDebug() << "VDefaultTools. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if ( parent->inherits("KarbonFactory") ) + { + KarbonToolRegistry* r = KarbonToolRegistry::instance(); + r->add(new KarbonToolFactory<VSelectTool>()); + r->add(new KarbonToolFactory<VSelectNodesTool>()); + r->add(new KarbonToolFactory<VRotateTool>()); + r->add(new KarbonToolFactory<VShearTool>()); + r->add(new KarbonToolFactory<VEllipseTool>()); + r->add(new KarbonToolFactory<VGradientTool>()); + r->add(new KarbonToolFactory<VPatternTool>()); + r->add(new KarbonToolFactory<VPencilTool>()); + r->add(new KarbonToolFactory<VPolygonTool>()); + r->add(new KarbonToolFactory<VPolylineTool>()); + r->add(new KarbonToolFactory<VRectangleTool>()); + r->add(new KarbonToolFactory<VRoundRectTool>()); + r->add(new KarbonToolFactory<VSinusTool>()); + r->add(new KarbonToolFactory<VSpiralTool>()); + r->add(new KarbonToolFactory<VStarTool>()); + r->add(new KarbonToolFactory<VTextTool>()); + } +} + +VDefaultTools::~VDefaultTools() +{ +} + +#include "vdefaulttools.moc" diff --git a/karbon/tools/vdefaulttools.h b/karbon/tools/vdefaulttools.h new file mode 100644 index 00000000..bb58bd8f --- /dev/null +++ b/karbon/tools/vdefaulttools.h @@ -0,0 +1,41 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __DEFAULTTOOLS_H__ +#define __DEFAULTTOOLS_H__ + +#include <qstring.h> + +#include <kparts/plugin.h> + +/** + * A module that provides the default tools + */ +class VDefaultTools : public KParts::Plugin +{ + Q_OBJECT +public: + VDefaultTools(QObject *parent, const char *name, const QStringList &); + virtual ~VDefaultTools(); +}; + +#endif // __DEFAULTTOOLS_H__ + + diff --git a/karbon/tools/vellipsetool.cc b/karbon/tools/vellipsetool.cc new file mode 100644 index 00000000..87528f4a --- /dev/null +++ b/karbon/tools/vellipsetool.cc @@ -0,0 +1,279 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qgroupbox.h> +#include <qlabel.h> + +#include <klocale.h> +#include "KoUnitWidgets.h" +#include <KoUnit.h> +#include <kcombobox.h> +#include <knuminput.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vellipse.h> +#include "vellipsetool.h" +#include "vglobal.h" + + +VEllipseOptionsWidget::VEllipseOptionsWidget( KarbonPart *part, QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Insert Ellipse" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + new QLabel( i18n( "Type:" ), group ); + m_type = new KComboBox( false, group ); + m_type->insertItem( i18n( "Full" ), VEllipse::full ); + m_type->insertItem( i18n( "Section" ), VEllipse::section ); + m_type->insertItem( i18n( "Pie" ), VEllipse::cut ); + m_type->insertItem( i18n( "Arc" ), VEllipse::arc ); + connect( m_type, SIGNAL( activated( int ) ), this, SLOT( typeChanged( int ) ) ); + + // add width/height-input: + m_widthLabel = new QLabel( i18n( "object width", "Width:" ), group ); + m_width = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + m_heightLabel = new QLabel( i18n( "Height:" ), group ); + m_height = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + + new QLabel( i18n( "Start angle:" ), group ); + m_startAngle = new KIntSpinBox( group ); + m_startAngle->setMinValue( 0 ); + m_startAngle->setMaxValue( 360 ); + + new QLabel( i18n( "End angle:" ), group ); + m_endAngle = new KIntSpinBox( group ); + m_endAngle->setMinValue( 0 ); + m_endAngle->setMaxValue( 360 ); + + typeChanged( VEllipse::full ); + + refreshUnit(); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +void +VEllipseOptionsWidget::typeChanged( int type ) +{ + m_startAngle->setEnabled( type != VEllipse::full ); + m_endAngle->setEnabled( type != VEllipse::full ); +} + +uint +VEllipseOptionsWidget::type() const +{ + return m_type->currentItem(); +} + +uint +VEllipseOptionsWidget::startAngle() const +{ + return m_startAngle->value(); +} + +uint +VEllipseOptionsWidget::endAngle() const +{ + return m_endAngle->value(); +} + +double +VEllipseOptionsWidget::width() const +{ + return m_width->value(); +} + +double +VEllipseOptionsWidget::height() const +{ + return m_height->value(); +} + +void +VEllipseOptionsWidget::setWidth( double value ) +{ + m_width->changeValue( value ); +} + +void +VEllipseOptionsWidget::setHeight( double value ) +{ + m_height->changeValue( value ); +} + +void +VEllipseOptionsWidget::refreshUnit () +{ + m_width->setUnit( m_part->unit() ); + m_height->setUnit( m_part->unit() ); +} + +VEllipseTool::VEllipseTool( KarbonView *view ) + : VShapeTool( view, "tool_ellipse" ) +{ + // create config dialog: + m_optionsWidget = new VEllipseOptionsWidget( view->part() ); + registerTool( this ); + + m_startAngle = m_endAngle = 0; + m_state = normal; +} + +VEllipseTool::~VEllipseTool() +{ + delete( m_optionsWidget ); +} + +void +VEllipseTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +VPath* +VEllipseTool::shape( bool interactive ) const +{ + if( interactive ) + { + double d1 = m_optionsWidget->width() / 2.0; + double d2 = m_optionsWidget->height() / 2.0; + return + new VEllipse( + 0L, + KoPoint( m_center.x() - d1, m_center.y() - d2 ), + d1 * 2.0, d2 * 2.0, + (VEllipse::VEllipseType)m_optionsWidget->type(), + m_optionsWidget->startAngle(), + m_optionsWidget->endAngle() ); + } + else + return + new VEllipse( + 0L, + KoPoint( m_center.x() - m_d1, m_center.y() - m_d2 ), + m_d1 * 2.0, + m_d2 * 2.0, + (VEllipse::VEllipseType)m_optionsWidget->type(), + m_startAngle, m_endAngle ); +} + +void +VEllipseTool::mouseMove() +{ + if( m_state == normal ) + return; + + draw(); + + //recalc(); + + if( m_state == startangle ) + { + m_startAngle = atan2( last().y() - m_center.y(), last().x() - m_center.x() ); + m_startAngle = ( m_startAngle / VGlobal::pi_2 ) * 90.0; + if( m_startAngle < 0 ) + m_startAngle += 360.0; + } + else + { + m_endAngle = atan2( last().y() - m_center.y(), last().x() - m_center.x() ); + m_endAngle = ( m_endAngle / VGlobal::pi_2 ) * 90.0; + if( m_endAngle < 0 ) + m_endAngle += 360.0; + } + + draw(); +} + +void +VEllipseTool::mouseDragRelease() +{ + if( m_optionsWidget->type() == VEllipse::full ) + VShapeTool::mouseDragRelease(); + + if( m_state == normal ) + if( m_optionsWidget->type() != VEllipse::full ) + m_state = startangle; +} + +void +VEllipseTool::mouseButtonPress() +{ + if( m_state == normal ) + { + VShapeTool::mouseButtonPress(); + m_center = first(); + } +} + +void +VEllipseTool::mouseButtonRelease() +{ + if( m_optionsWidget->type() == VEllipse::full || m_state == normal ) + VShapeTool::mouseButtonRelease(); + + if( m_state == startangle ) + m_state = endangle; + else if( m_state == endangle ) + { + VShapeTool::mouseDragRelease(); + m_startAngle = m_endAngle = 0; + m_state = normal; + } +} + +void +VEllipseTool::cancel() +{ + if( isDragging() ) + VShapeTool::cancel(); + else + draw(); + + m_startAngle = m_endAngle = 0; + m_state = normal; +} + +bool +VEllipseTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VEllipseTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Ellipse Tool" ), "14_ellipse", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Ellipse" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + +#include "vellipsetool.moc" + diff --git a/karbon/tools/vellipsetool.h b/karbon/tools/vellipsetool.h new file mode 100644 index 00000000..d30e3411 --- /dev/null +++ b/karbon/tools/vellipsetool.h @@ -0,0 +1,91 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VELLIPSETOOL_H__ +#define __VELLIPSETOOL_H__ + +#include <kdialogbase.h> + +#include "vshapetool.h" + +class KoUnitDoubleSpinBox; +class KComboBox; +class KIntSpinBox; +class KarbonView; +class QLabel; +class QWidget; + +class VEllipseOptionsWidget : public KDialogBase +{ +Q_OBJECT +public: + VEllipseOptionsWidget( KarbonPart *part, QWidget *parent = 0L, const char *name = 0L ); + + double width() const; + double height() const; + uint startAngle() const; + uint endAngle() const; + uint type() const; + void setWidth( double value ); + void setHeight( double value ); + void refreshUnit(); + +public slots: + void typeChanged( int ); + +private: + KComboBox *m_type; + KIntSpinBox *m_startAngle; + KIntSpinBox *m_endAngle; + KoUnitDoubleSpinBox *m_width; + KoUnitDoubleSpinBox *m_height; + KarbonPart *m_part; + QLabel *m_heightLabel; + QLabel *m_widthLabel; +}; + +class VEllipseTool : public VShapeTool +{ +public: + VEllipseTool( KarbonView *view ); + virtual ~VEllipseTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Ellipse Tool" ); } + virtual VPath *shape( bool interactive = false ) const; + void refreshUnit(); + +protected: + void mouseDragRelease(); + void mouseMove(); + void mouseButtonPress(); + void mouseButtonRelease(); + void cancel(); + +private: + enum { normal, startangle, endangle } m_state; + VEllipseOptionsWidget *m_optionsWidget; + double m_startAngle; + double m_endAngle; + KoPoint m_center; +}; + +#endif + diff --git a/karbon/tools/vgradienttool.cc b/karbon/tools/vgradienttool.cc new file mode 100644 index 00000000..dbd82720 --- /dev/null +++ b/karbon/tools/vgradienttool.cc @@ -0,0 +1,526 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcursor.h> +#include <qlabel.h> + +#include <klocale.h> + +#include <karbon_part.h> +#include <karbon_view.h> +#include <karbon_factory.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include "vgradienttool.h" +#include <widgets/vgradienttabwidget.h> +#include <commands/vfillcmd.h> +#include <commands/vstrokecmd.h> +#include <core/vstroke.h> +#include <core/vselection.h> +#include <widgets/vstrokefillpreview.h> + +#include <kdebug.h> + +VGradientTool::VGradientOptionsWidget::VGradientOptionsWidget( VGradient& gradient ) + : KDialogBase( 0L, "", true, i18n( "Edit Gradient" ), Ok | Cancel ) +{ + m_gradientWidget = new VGradientTabWidget( gradient, KarbonFactory::rServer(), this ); + setMainWidget( m_gradientWidget ); + setFixedSize( baseSize() ); +} + +VGradientTool::VGradientTool( KarbonView *view ) + : VTool( view, "gradienttool" ), m_state( normal ), m_handleSize( 3 ), m_active( false ) +{ + setName( "tool_gradient" ); + m_optionsWidget = new VGradientOptionsWidget( m_gradient ); + registerTool( this ); +} + +VGradientTool::~VGradientTool() +{ + delete m_optionsWidget; +} + +void +VGradientTool::activate() +{ + m_active = true; + m_state = normal; + view()->statusMessage()->setText( i18n( "Gradient" ) ); + view()->setCursor( QCursor( Qt::crossCursor ) ); + VTool::activate(); + + if( view() ) + { + // disable selection handles + view()->part()->document().selection()->showHandle( false ); + // connect to the stroke-fill-preview to get notice when the stroke or fill gets selected + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( preview ) + { + connect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) ); + connect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) ); + } + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VGradientTool::deactivate() +{ + m_active = false; + + if( view() ) + { + // enable selection handles + view()->part()->document().selection()->showHandle( true ); + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( preview ) + { + disconnect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) ); + disconnect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) ); + } + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +QString +VGradientTool::statusText() +{ + return i18n( "Gradient Tool" ); +} + +QString +VGradientTool::contextHelp() +{ + QString s = i18n( "<qt><b>Gradient tool:</b><br>" ); + s += i18n( "<i>Click and drag</i> to choose the gradient vector.<br>" ); + s += i18n( "<i>Click and drag</i> a gradient vector handle to change the gradient vector.<br>" ); + s += i18n( "<i>Shift click and drag</i> to move the radial gradient focal point.<br>" ); + s += i18n( "<i>Press i or Shift+i</i> to decrease or increase the handle size.<br>" ); + s += i18n( "<br><b>Gradient editing:</b><br>" ); + s += i18n( "<i>Click and drag</i> to move points.<br>" ); + s += i18n( "<i>Double click</i> on a color point to edit it.<br>" ); + s += i18n( "<i>Right click</i> on a color point to remove it.</qt>" ); + return s; +} + +bool +VGradientTool::getGradient( VGradient &gradient ) +{ + if( ! view() ) + return false; + + // determine if stroke of fill is selected for editing + VStrokeFillPreview *preview = view()->strokeFillPreview(); + bool strokeSelected = ( preview && preview->strokeIsSelected() ); + + VSelection* selection = view()->part()->document().selection(); + if( selection->objects().count() != 1 ) + return false; + + VObject *obj = selection->objects().getFirst(); + // get the gradient of the first selected object, if any + if( strokeSelected && obj->stroke()->type() == VStroke::grad ) + gradient = obj->stroke()->gradient(); + else if( ! strokeSelected && obj->fill()->type() == VFill::grad ) + gradient = obj->fill()->gradient(); + else + return false; + + return true; +} + +bool +VGradientTool::getOpacity( double &opacity ) +{ + if( ! view() ) + return false; + + // determine if stroke of fill is selected for editing + VStrokeFillPreview *preview = view()->strokeFillPreview(); + bool strokeSelected = ( preview && preview->strokeIsSelected() ); + + VSelection* selection = view()->part()->document().selection(); + if( selection->objects().count() != 1 ) + return false; + + VObject *obj = selection->objects().getFirst(); + // get the opacity of the first selected object, if any + if( strokeSelected && obj->stroke()->type() == VStroke::grad ) + opacity = obj->stroke()->color().opacity(); + else if( ! strokeSelected && obj->fill()->type() == VFill::grad ) + opacity = obj->fill()->color().opacity(); + else return false; + + return true; +} + +void +VGradientTool::draw( VPainter* painter ) +{ + if( ! m_active ) + return; + + if( m_state != normal ) + return; + + if( ! getGradient( m_gradient ) ) + return; + + KoPoint s = m_gradient.origin(); + KoPoint e = m_gradient.vector(); + KoPoint f = m_gradient.focalPoint(); + + // save the handle rects for later inside testing + m_origin = KoRect( s.x()-m_handleSize, s.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize ); + m_vector = KoRect( e.x()-m_handleSize, e.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize ); + m_center = KoRect( f.x()-m_handleSize, f.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize ); + + painter->setPen( Qt::blue.light() ); + painter->setBrush( Qt::blue.light() ); + painter->setRasterOp( Qt::XorROP ); + + // draw the gradient vector + painter->newPath(); + painter->moveTo( s ); + painter->lineTo( e ); + painter->strokePath(); + + if( m_gradient.type() == VGradient::radial ) + { + // draw the focal point cross + double size = (double)m_handleSize / view()->zoom(); + KoPoint focal = m_center.center(); + KoRect cross = KoRect( focal.x()-3*size, focal.y()-3*size, 6*size, 6*size ); + painter->newPath(); + painter->moveTo( cross.topLeft() ); + painter->lineTo( cross.bottomRight() ); + painter->strokePath(); + painter->newPath(); + painter->moveTo( cross.bottomLeft() ); + painter->lineTo( cross.topRight() ); + painter->strokePath(); + } + // draw the handle rects + painter->drawNode( m_origin.center(), m_handleSize ); + painter->drawNode( m_vector.center(), m_handleSize ); +} + +void +VGradientTool::draw() +{ + if( ! view() || view()->part()->document().selection()->objects().count() == 0 ) + return; + + VPainter *painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + painter->setPen( Qt::DotLine ); + painter->newPath(); + + // differentiate between moving a handle and creating a complete new vector + if( m_state == moveOrigin || m_state == moveVector ) + { + painter->moveTo( m_fixed ); + painter->lineTo( m_current ); + // draw the handle rects + painter->drawNode( m_fixed, m_handleSize ); + painter->drawNode( m_current, m_handleSize ); + } + else if( m_state == createNew ) + { + painter->moveTo( first() ); + painter->lineTo( m_current ); + // draw the handle rects + painter->drawNode( first(), m_handleSize ); + painter->drawNode( m_current, m_handleSize ); + } + else if( m_state == moveCenter ) + { + // draw the focal point cross + double size = (double)m_handleSize / view()->zoom(); + KoRect cross = KoRect( m_current.x()-3*size, m_current.y()-3*size, 6*size, 6*size ); + painter->moveTo( cross.topLeft() ); + painter->lineTo( cross.bottomRight() ); + painter->strokePath(); + painter->newPath(); + painter->moveTo( cross.bottomLeft() ); + painter->lineTo( cross.topRight() ); + } + + painter->strokePath(); +} + +void +VGradientTool::mouseDrag() +{ + if( m_state == normal ) + return; + + // undo old line + draw(); + + m_current = last(); + + draw(); +} + +void +VGradientTool::mouseButtonPress() +{ + m_current = first(); + + // set the apropriate editing state + if( m_center.contains( m_current ) && shiftPressed()) + { + m_state = moveCenter; + } + else if( m_origin.contains( m_current ) ) + { + m_state = moveOrigin; + m_fixed = m_vector.center(); + } + else if( m_vector.contains( m_current ) ) + { + m_state = moveVector; + m_fixed = m_origin.center(); + } + else + m_state = createNew; +} + +void +VGradientTool::mouseButtonRelease() +{ + m_state = normal; + + if( ! view() || view()->part()->document().selection()->objects().count() == 0 ) + return; + + // save old gradient position + VGradient oldGradient = m_gradient; + + bool strokeSelected = false; + + // determine the target from the stroke-fill-preview-widget + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( preview && preview->strokeIsSelected() ) + strokeSelected = true; + + if( first() == last() ) + { + m_optionsWidget->gradientWidget()->setGradient( m_gradient ); + if( strokeSelected ) + { + m_optionsWidget->gradientWidget()->setTarget( VGradientTabWidget::STROKE ); + m_optionsWidget->gradientWidget()->setOpacity( 1.0 ); + } + else + { + m_optionsWidget->gradientWidget()->setTarget( VGradientTabWidget::FILL ); + double opacity; + if( getOpacity( opacity ) ) + m_optionsWidget->gradientWidget()->setOpacity( opacity ); + } + + if( ! showDialog() ) + return; + + m_gradient = m_optionsWidget->gradientWidget()->gradient(); + + // if the gradient dialog was shown and accepted, determine the target from the dialog + strokeSelected = ( m_optionsWidget->gradientWidget()->target() == VGradientTabWidget::STROKE ); + } + + // calculate a sane intial position for the new gradient + if( view()->part()->document().selection()->objects().count() == 1 ) + { + VObject *obj = view()->part()->document().selection()->objects().getFirst(); + + if( ( ! strokeSelected && obj->fill()->type() != VFill::grad ) + || ( strokeSelected && obj->stroke()->type() != VStroke::grad ) ) + { + KoRect bbox = obj->boundingBox(); + switch( m_gradient.type() ) + { + case VGradient::linear: + oldGradient.setOrigin( bbox.bottomLeft() + 0.5*(bbox.bottomRight()-bbox.bottomLeft()) ); + oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) ); + oldGradient.setFocalPoint( bbox.center() ); + break; + case VGradient::radial: + oldGradient.setOrigin( bbox.center() ); + oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) ); + oldGradient.setFocalPoint( bbox.center() ); + break; + case VGradient::conic: + oldGradient.setOrigin( bbox.center() ); + oldGradient.setVector( bbox.topLeft() + 0.5*(bbox.topRight()-bbox.topLeft()) ); + oldGradient.setFocalPoint( bbox.center() ); + break; + } + } + } + + // workaround for a libart 2.3.10 bug + if( oldGradient.origin() == oldGradient.vector() ) + oldGradient.vector().rx()+=1; + + // use the old gradient position + m_gradient.setVector( oldGradient.vector() ); + m_gradient.setOrigin( oldGradient.origin() ); + m_gradient.setFocalPoint( oldGradient.focalPoint() ); + + if( ! strokeSelected ) + { + VFill fill; + fill.gradient() = m_gradient; + fill.setType( VFill::grad ); + VColor c = fill.color(); + c.setOpacity( m_optionsWidget->gradientWidget()->opacity() ); + fill.setColor( c, false ); + view()->part()->addCommand( + new VFillCmd( &view()->part()->document(), fill, "14_gradient" ), true ); + } + else + { + view()->part()->addCommand( + new VStrokeCmd( &view()->part()->document(), &m_gradient ), true ); + } +} + +void +VGradientTool::mouseDragRelease() +{ + if( ! view() || m_state == normal ) + return; + + if( view()->part()->document().selection()->objects().count() == 0 ) + { + draw(); + return; + } + + if( m_state == moveOrigin ) + m_gradient.setOrigin( last() ); + else if( m_state == moveVector ) + m_gradient.setVector( last() ); + else if( m_state == moveCenter ) + m_gradient.setFocalPoint( last() ); + else if( m_state == createNew ) + { + m_gradient.setOrigin( first() ); + m_gradient.setFocalPoint( first() ); + m_gradient.setVector( last() ); + } + + m_state = normal; + + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( ! preview ) + return; + + if( ! preview->strokeIsSelected() ) + { + VFill fill; + fill.gradient() = m_gradient; + fill.setType( VFill::grad ); + VColor c = fill.color(); + c.setOpacity( m_optionsWidget->gradientWidget()->opacity() ); + fill.setColor( c, false ); + view()->part()->addCommand( + new VFillCmd( &view()->part()->document(), fill, "14_gradient" ), true ); + } + else + view()->part()->addCommand( + new VStrokeCmd( &view()->part()->document(), &m_gradient ), true ); +} + +void +VGradientTool::cancel() +{ + // Erase old object: + if( isDragging() ) + draw(); + m_state = normal; +} + +bool +VGradientTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VGradientTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Gradient Tool" ), "14_gradient", Qt::Key_G, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Gradient" ) ); + m_action->setExclusiveGroup( "misc" ); + //m_ownAction = true; + } +} + +void +VGradientTool::setCursor() const +{ + if( !view() ) return; + + // set a different cursor if mouse is inside the handle rects + if( m_origin.contains( last() ) || m_vector.contains( last() ) || m_center.contains( last() ) ) + view()->setCursor( QCursor( Qt::SizeAllCursor ) ); + else + view()->setCursor( QCursor( Qt::arrowCursor ) ); +} + +bool +VGradientTool::keyReleased( Qt::Key key ) +{ + // increase/decrease the handle size + switch( key ) + { + case Qt::Key_I: + if( shiftPressed() ) + m_handleSize++; + else if( m_handleSize > 3 ) + m_handleSize--; + break; + default: return false; + } + + if( view() ) + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + + return true; +} + +void +VGradientTool::targetChanged() +{ + if( view() ) + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); +} + +#include "vgradienttool.moc" diff --git a/karbon/tools/vgradienttool.h b/karbon/tools/vgradienttool.h new file mode 100644 index 00000000..7e78d510 --- /dev/null +++ b/karbon/tools/vgradienttool.h @@ -0,0 +1,98 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VGRADIENTTOOL_H__ +#define __VGRADIENTTOOL_H__ + +#include <kdialogbase.h> + +#include "vtool.h" +#include "vgradient.h" +#include "KoRect.h" + +class VGradientTabWidget; + +class VGradientTool : public VTool +{ + Q_OBJECT + +public: + VGradientTool( KarbonView *view ); + virtual ~VGradientTool(); + + virtual void activate(); + virtual void deactivate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Gradient Tool" ); } + virtual QString statusText(); + + virtual QString contextHelp(); + virtual bool showDialog() const; + + virtual void draw( VPainter* painter ); + +protected: + + virtual void draw(); + virtual void mouseButtonRelease(); + virtual void mouseButtonPress(); + virtual void mouseDragRelease(); + virtual void mouseDrag(); + virtual void cancel(); + virtual void setCursor() const; + virtual bool keyReleased( Qt::Key key ); + + /** + * Determines the actual gradient to be edited. + * + * @param gradient the found gradient + * @return true if gradient was found, else false + */ + bool getGradient( VGradient &gradient ); + + bool getOpacity( double &opacity ); + +protected slots: + void targetChanged(); + +private: + enum { normal, moveOrigin, moveVector, moveCenter, createNew } m_state; + + class VGradientOptionsWidget : public KDialogBase + { + public: + VGradientOptionsWidget( VGradient& gradient ); + VGradientTabWidget *gradientWidget() { return m_gradientWidget; } + private: + VGradientTabWidget *m_gradientWidget; + }; + VGradient m_gradient; /**< the actual gradient */ + KoPoint m_current; /**< the current position when dragging */ + KoPoint m_fixed; /**< the fixed point when only dragging one point of the gradient vector */ + VGradientOptionsWidget* m_optionsWidget; /**< the options dialog, for editing gradients */ + KoRect m_origin; /**< the handle of the gradient origin */ + KoRect m_vector; /**< the handle of the gradient vector */ + KoRect m_center; /**< the handle of the radial gradient focal point */ + int m_handleSize; /**< the handle's size */ + bool m_active; /**< holds active state of the tool, which is used for drawing of the gradient vector */ +}; + +#endif + diff --git a/karbon/tools/vpatterntool.cc b/karbon/tools/vpatterntool.cc new file mode 100644 index 00000000..0143d0bc --- /dev/null +++ b/karbon/tools/vpatterntool.cc @@ -0,0 +1,509 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vpatterntool.h" + +#include <qtoolbutton.h> +#include <qframe.h> +#include <qhbuttongroup.h> +#include <qlayout.h> +#include <qfileinfo.h> +#include <qlabel.h> +#include <qcursor.h> + +#include <kiconloader.h> +#include <koIconChooser.h> +#include <kfiledialog.h> +#include <kmessagebox.h> + +#include <karbon_factory.h> +#include <karbon_resourceserver.h> +#include <karbon_view.h> +#include <karbon_part.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <core/vselection.h> +#include <core/vfill.h> +#include <core/vstroke.h> +#include <commands/vfillcmd.h> +#include <commands/vstrokecmd.h> +#include <widgets/vstrokefillpreview.h> + +VPatternWidget::VPatternWidget( QPtrList<KoIconItem>* patterns, VTool*, QWidget* parent ) + : KDialogBase( parent, "", true, i18n( "Choose Pattern" ), Ok | Cancel ), m_pattern( 0 ) +{ + QWidget *base = new QWidget( this ); + QVBoxLayout* layout = new QVBoxLayout( base ); + layout->addWidget( m_patternChooser = new KoIconChooser( QSize( 32, 32 ), base ) ); + layout->addWidget( m_buttonGroup = new QHButtonGroup( base ) ); + m_buttonGroup->insert( m_importPatternButton = new QToolButton( m_buttonGroup ) ); + m_buttonGroup->insert( m_deletePatternButton = new QToolButton( m_buttonGroup ) ); + m_patternChooser->setFixedSize( 180, 120 ); + m_importPatternButton->setIconSet( SmallIconSet( "14_layer_newlayer" ) ); + m_importPatternButton->setTextLabel( i18n( "Import" ) ); + m_deletePatternButton->setIconSet( SmallIconSet("14_layer_deletelayer" ) ); + m_deletePatternButton->setTextLabel( i18n( "Delete" ) ); + + m_buttonGroup->setInsideMargin( 3 ); + m_importPatternButton->setEnabled( true ); + m_deletePatternButton->setEnabled( false ); + + //setFrameStyle( Box | Sunken ); + layout->setMargin( 3 ); + + connect( m_buttonGroup, SIGNAL( clicked( int ) ), this, SLOT( slotButtonClicked( int ) ) ); + connect( m_patternChooser, SIGNAL( selected( KoIconItem* ) ), this, SLOT( patternSelected( KoIconItem* ) ) ); + + KoIconItem* item; + for( item = patterns->first(); item; item = patterns->next() ) + m_patternChooser->addItem( item ); + m_pattern = (VPattern*)patterns->first(); + + setMainWidget( base ); +} // VPatternWidget::VPatternWidget + +VPatternWidget::~VPatternWidget() +{ +} // VPatternWidget::~VPatternWidget + +VPattern* VPatternWidget::selectedPattern() +{ + return m_pattern; +} // VPatternWidget::selectedPattern + +void VPatternWidget::importPattern() +{ + VPattern* pattern = KarbonFactory::rServer()->addPattern( KFileDialog::getOpenFileName( QString::null, + "*.jpg *.gif *.png *.tif *.xpm *.bmp", this, i18n( "Choose Pattern to Add" ) ) ); + if( pattern ) + m_patternChooser->addItem( pattern ); +} // VPatternWidget::importPattern + +void VPatternWidget::deletePattern() +{ + m_patternChooser->removeItem( m_pattern ); + KarbonFactory::rServer()->removePattern( m_pattern ); + m_patternChooser->updateContents(); + m_pattern = static_cast<VPattern*>( m_patternChooser->currentItem() ); +} // VPatternWidget::deletePattern + +void VPatternWidget::slotButtonClicked( int id ) +{ + switch( id ) + { + case 0: importPattern(); + break; + case 1: deletePattern(); + break; + } +} // VPatternWidget::slotButtonClicked + +void VPatternWidget::patternSelected( KoIconItem* item ) +{ + m_pattern = (VPattern*)item; + m_deletePatternButton->setEnabled( QFileInfo( m_pattern->tilename() ).isWritable() ); +} // VPatternWidget::patternSelected + +VPatternTool::VPatternTool( KarbonView *view ) + : VTool( view, "tool_pattern" ), m_state( normal ), m_handleSize( 3 ), m_active( false ) +{ + QPtrList<KoIconItem> patterns = KarbonFactory::rServer()->patterns(); + m_optionsWidget = new VPatternWidget( &patterns, this ); + registerTool( this ); +} // VPatternTool::VPatternTool + +VPatternTool::~VPatternTool() +{ + delete m_optionsWidget; +} // VPatternTool::~VPatternTool + +void +VPatternTool::activate() +{ + m_active = true; + m_state = normal; + VTool::activate(); + view()->statusMessage()->setText( i18n( "Pattern" ) ); + view()->setCursor( QCursor( Qt::crossCursor ) ); + + if( view() ) + { + // disable selection handles + view()->part()->document().selection()->showHandle( false ); + // connect to the stroke-fill-preview to get notice when the stroke or fill gets selected + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( preview ) + { + connect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) ); + connect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) ); + } + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VPatternTool::deactivate() +{ + m_active = false; + + if( view() ) + { + // enable selection handles + view()->part()->document().selection()->showHandle( true ); + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( preview ) + { + disconnect( preview, SIGNAL( fillSelected() ), this, SLOT( targetChanged() ) ); + disconnect( preview, SIGNAL( strokeSelected() ), this, SLOT( targetChanged() ) ); + } + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + + +QString +VPatternTool::contextHelp() +{ + QString s = i18n( "<qt><b>Pattern tool:</b><br>" ); + s += i18n( "<i>Click</i> on the pattern you want in the chooser.<br>" ); + s += i18n( "<i>Click and drag</i> to choose the pattern vector.</qt>" ); + s += i18n( "<i>Press i or Shift+i</i> to decrease or increase the handle size.<br>" ); + return s; +} // VPatternTool::contextHelp + +void VPatternTool::draw() +{ + if( ! view() || view()->part()->document().selection()->objects().count() == 0 ) + return; + + VPainter *painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + painter->setPen( Qt::DotLine ); + + // differentiate between moving a handle and creating a complete new vector + if( m_state == moveOrigin || m_state == moveVector ) + { + painter->newPath(); + painter->moveTo( m_fixed ); + painter->lineTo( m_current ); + painter->strokePath(); + // draw the handle rects + painter->drawNode( m_fixed, m_handleSize ); + painter->drawNode( m_current, m_handleSize ); + } + else if( m_state == createNew ) + { + painter->newPath(); + painter->moveTo( first() ); + painter->lineTo( m_current ); + painter->strokePath(); + // draw the handle rects + painter->drawNode( first(), m_handleSize ); + painter->drawNode( m_current, m_handleSize ); + } +} // VPatternTool::draw + +bool +VPatternTool::getPattern( VPattern &pattern ) +{ + if( ! view() ) + return false; + + // determine if stroke of fill is selected for editing + //VStrokeFillPreview *preview = view()->strokeFillPreview(); + //bool strokeSelected = ( preview && preview->strokeIsSelected() ); + bool strokeSelected = false; // FIXME: stroke patterns don't work + + VSelection* selection = view()->part()->document().selection(); + if( selection->objects().count() != 1 ) + return false; + + VObject *obj = selection->objects().getFirst(); + // get the pattern of the first selected object, if any + if( strokeSelected && obj->stroke()->type() == VStroke::patt ) + pattern = obj->stroke()->pattern(); + else if( ! strokeSelected && obj->fill()->type() == VFill::patt ) + pattern = obj->fill()->pattern(); + else + return false; + + return true; +} + +void +VPatternTool::draw( VPainter* painter ) +{ + if( ! m_active ) + return; + + if( m_state != normal ) + return; + + if( ! getPattern( m_pattern ) ) + return; + + KoPoint s = m_pattern.origin(); + KoPoint e = m_pattern.vector(); + + // save the handle rects for later inside testing + m_origin = KoRect( s.x()-m_handleSize, s.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize ); + m_vector = KoRect( e.x()-m_handleSize, e.y()-m_handleSize, 2*m_handleSize, 2*m_handleSize ); + + painter->setPen( Qt::blue.light() ); + painter->setBrush( Qt::blue.light() ); + painter->setRasterOp( Qt::XorROP ); + + // draw the pattern vector + painter->newPath(); + painter->moveTo( s ); + painter->lineTo( e ); + painter->strokePath(); + + // draw the handle rects + painter->drawNode( m_origin.center(), m_handleSize ); + painter->drawNode( m_vector.center(), m_handleSize ); +} + +void +VPatternTool::mouseDrag() +{ + if( m_state == normal ) + return; + + draw(); + + m_current = last(); + + draw(); +} // VPatternTool::mouseDrag + +void +VPatternTool::mouseButtonPress() +{ + m_current = first(); + + // set the apropriate editing state + if( m_origin.contains( m_current ) ) + { + m_state = moveOrigin; + m_fixed = m_vector.center(); + } + else if( m_vector.contains( m_current ) ) + { + m_state = moveVector; + m_fixed = m_origin.center(); + } + else + m_state = createNew; +} // VPatternTool::mouseButtonPress + +void +VPatternTool::mouseButtonRelease() +{ + m_state = normal; + + if( view()->part()->document().selection()->objects().count() == 0 ) + return; + + // save old pattern position + VPattern oldPattern = m_pattern; + + if( first() == last() ) + { + if( showDialog() != QDialog::Accepted ) + return; + } + + if( !m_optionsWidget->selectedPattern() ) + { + KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" ); + return; + } + + bool strokeSelected = false; + + // determine the target from the stroke-fill-preview-widget + //VStrokeFillPreview* preview = view()->strokeFillPreview(); + //if( preview && preview->strokeIsSelected() ) // FIXME: stroke patterns don't work + // strokeSelected = true; + + // calculate a sane intial position for the new pattern + if( view()->part()->document().selection()->objects().count() == 1 ) + { + VObject *obj = view()->part()->document().selection()->objects().getFirst(); + + if( ( ! strokeSelected && obj->fill()->type() != VFill::patt ) || (strokeSelected && obj->stroke()->type() != VStroke::patt ) ) + { + KoRect bbox = obj->boundingBox(); + oldPattern.setOrigin( bbox.bottomLeft() + 0.5*(bbox.topLeft()-bbox.bottomLeft()) ); + oldPattern.setVector( bbox.bottomRight() + 0.5*(bbox.topRight()-bbox.bottomRight()) ); + } + } + + m_pattern = *m_optionsWidget->selectedPattern(); + + // use the old pattern position + m_pattern.setOrigin( oldPattern.origin() ); + m_pattern.setVector( oldPattern.vector() ); + + if( ! strokeSelected ) + { + VFill fill; + fill.pattern() = m_pattern; + fill.setType( VFill::patt ); + view()->part()->addCommand( + new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true ); + } + else + { + VStroke stroke; + stroke.pattern() = m_pattern; + stroke.setType( VStroke::patt ); + view()->part()->addCommand( + new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true ); + } +} // VPatternTool::mouseButtonRelease + +void +VPatternTool::mouseDragRelease() +{ + if( ! view() || m_state == normal ) + return; + + if( view()->part()->document().selection()->objects().count() == 0 ) + { + draw(); + return; + } + + if( !m_optionsWidget->selectedPattern() ) + { + draw(); + KMessageBox::error( 0L, i18n( "Please select a pattern." ), "" ); + return; + } + //m_pattern = *m_optionsWidget->selectedPattern(); + + if( m_state == moveOrigin ) + m_pattern.setOrigin( last() ); + else if( m_state == moveVector ) + m_pattern.setVector( last() ); + else if( m_state == createNew ) + { + m_pattern.setOrigin( first() ); + m_pattern.setVector( last() ); + } + + m_state = normal; + + VStrokeFillPreview* preview = view()->strokeFillPreview(); + if( ! preview ) + return; + + //if( ! preview->strokeIsSelected() ) // FIXME: stroke patterns don't work + { + VFill fill; + fill.pattern() = m_pattern; + fill.setType( VFill::patt ); + view()->part()->addCommand( + new VFillCmd( &view()->part()->document(), fill, "14_pattern" ), true ); + } + /* + else + { + VStroke stroke; + stroke.pattern() = m_pattern; + stroke.setType( VStroke::patt ); + view()->part()->addCommand( + new VStrokeCmd( &view()->part()->document(), &stroke, "14_pattern" ), true ); + } + */ +} // VPatternTool::mouseDragRelease + +void +VPatternTool::cancel() +{ + // Erase old object: + if( isDragging() ) + draw(); + m_state = normal; +} + +bool +VPatternTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VPatternTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Pattern Tool" ), "14_pattern", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Pattern" ) ); + m_action->setExclusiveGroup( "misc" ); + //m_ownAction = true; + } +} + +void +VPatternTool::setCursor() const +{ + if( !view() ) return; + + // set a different cursor if mouse is inside the handle rects + if( m_origin.contains( last() ) || m_vector.contains( last() ) ) + view()->setCursor( QCursor( Qt::SizeAllCursor ) ); + else + view()->setCursor( QCursor( Qt::arrowCursor ) ); +} + +bool +VPatternTool::keyReleased( Qt::Key key ) +{ + // increase/decrease the handle size + switch( key ) + { + case Qt::Key_I: + if( shiftPressed() ) + m_handleSize++; + else if( m_handleSize > 3 ) + m_handleSize--; + break; + default: return false; + } + + if( view() ) + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + + return true; +} + +void +VPatternTool::targetChanged() +{ + if( view() ) + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); +} + +#include "vpatterntool.moc" diff --git a/karbon/tools/vpatterntool.h b/karbon/tools/vpatterntool.h new file mode 100644 index 00000000..0a89a4d4 --- /dev/null +++ b/karbon/tools/vpatterntool.h @@ -0,0 +1,116 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPATTERNTOOL_H__ +#define __VPATTERNTOOL_H__ + +#include <kdialogbase.h> + +#include "vtool.h" +#include "vpattern.h" +#include "KoRect.h" + +class QHButtonGroup; +class QToolButton; +class KoIconChooser; + +class VPatternWidget : public KDialogBase +{ +Q_OBJECT + +public: + VPatternWidget( QPtrList<KoIconItem>* patterns, VTool* tool, QWidget* parent = 0L ); + ~VPatternWidget(); + + VPattern* selectedPattern(); + +public slots: + void importPattern(); + void deletePattern(); + + void slotButtonClicked( int id ); + void patternSelected( KoIconItem* ); + +private: + KoIconChooser* m_patternChooser; + QHButtonGroup* m_buttonGroup; + QToolButton* m_importPatternButton; + QToolButton* m_deletePatternButton; + VTool* m_tool; + VPattern* m_pattern; +}; // VPatternWidget + + +class VPatternTool : public VTool +{ + Q_OBJECT + +public: + VPatternTool( KarbonView *view ); + virtual ~VPatternTool(); + + virtual void activate(); + virtual void deactivate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Pattern Tool" ); } + virtual QString contextHelp(); + virtual bool showDialog() const; + + virtual void draw( VPainter* painter ); + +protected: + virtual void draw(); + + virtual void mouseButtonRelease(); + virtual void mouseButtonPress(); + virtual void mouseDragRelease(); + virtual void mouseDrag(); + /*virtual void mouseDragShiftPressed(); // To use to scale the pattern. + virtual void mouseDragShiftReleased(); */ + virtual void cancel(); + virtual void setCursor() const; + virtual bool keyReleased( Qt::Key key ); + + /** + * Determines the actual pattern to be edited. + * + * @param pattern the found pattern + * @return true if pattern was found, else false + */ + bool getPattern( VPattern &pattern ); + +protected slots: + void targetChanged(); + +private: + enum { normal, moveOrigin, moveVector, createNew } m_state; + + VPattern m_pattern; + KoPoint m_current; /**< the current position when dragging */ + KoPoint m_fixed; /**< the fixed point when only dragging one point of the gradient vector */ + VPatternWidget* m_optionsWidget; /**< the options dialog, for selecting patterns */ + KoRect m_origin; /**< the handle of the pattern origin */ + KoRect m_vector; /**< the handle of the pattern vector */ + int m_handleSize; /**< the handle's size */ + bool m_active; /**< holds active state of the tool, which is used for drawing of the pattern vector */ +}; // VPatternTool + +#endif /* __VPATTERNTOOL_H__ */ + diff --git a/karbon/tools/vpenciltool.cc b/karbon/tools/vpenciltool.cc new file mode 100644 index 00000000..3a18fcb0 --- /dev/null +++ b/karbon/tools/vpenciltool.cc @@ -0,0 +1,411 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ +#include <math.h> + +#include <qcursor.h> +#include <qevent.h> +#include <qlabel.h> +#include <qgroupbox.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qvbox.h> +#include <qwidgetstack.h> + +#include <klocale.h> +#include <knuminput.h> +//#include <KoUnitWidgets.h> + +#include <karbon_part.h> +#include <karbon_view.h> + +#include <core/vcolor.h> +#include <core/vcomposite.h> +#include <core/vfill.h> +#include <core/vstroke.h> +#include <core/vglobal.h> +#include <core/vselection.h> +#include <core/vcursor.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include "vpenciltool.h" +#include <commands/vshapecmd.h> + +#include "vcurvefit.h" + +#include "vpenciltool.moc" + +VPencilOptionsWidget::VPencilOptionsWidget( KarbonView*view, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Pencil Settings" ), Ok | Cancel ), m_view( view ) +{ + QVBox *vbox = new QVBox( this ); + + m_combo = new QComboBox( vbox ); + + m_combo->insertItem( i18n( "Raw" ) ); + m_combo->insertItem( i18n( "Curve" ) ); + m_combo->insertItem( i18n( "Straight" ) ); + + m_widgetStack = new QWidgetStack( vbox ); + + QGroupBox *group1 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack ); + m_widgetStack->addWidget( group1, 1 ); + m_optimizeRaw = new QCheckBox( i18n( "Optimize" ), group1 ); + + group1->setInsideMargin( 4 ); + group1->setInsideSpacing( 2 ); + + QGroupBox *group2 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack ); + m_widgetStack->addWidget( group2, 2 ); + + QVBox *vbox2 = new QVBox( group2 ); + + m_optimizeCurve = new QCheckBox( i18n( "Optimize" ), vbox2 ); + m_fittingError = new KDoubleNumInput( 0.0, 400.0, 4.00, 0.50, 3, vbox2 ); + m_fittingError->setLabel( i18n( "Exactness:" ) ); + + group2->setInsideMargin( 4 ); + group2->setInsideSpacing( 2 ); + + QGroupBox *group3 = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), m_widgetStack ); + m_widgetStack->addWidget( group3, 3 ); + + m_combineAngle = new KDoubleNumInput( 0.0, 360.0, 0.10, 0.50, 3, group3 ); + m_combineAngle->setSuffix( " deg" ); + m_combineAngle->setLabel( i18n( "Combine angle:" ) ); + + group3->setInsideMargin( 4 ); + group3->setInsideSpacing( 2 ); + + connect( m_combo, SIGNAL( activated( int ) ), this, SLOT( selectMode() ) ); + + //Set the default settings + m_mode = VPencilTool::CURVE; + selectMode(); + + m_optimizeCurve->setChecked( true ); + m_optimizeRaw->setChecked( true ); + + setMainWidget( vbox ); +} + +float VPencilOptionsWidget::combineAngle() +{ + return m_combineAngle->value(); +} + +bool VPencilOptionsWidget::optimize() +{ + return ( m_optimizeRaw->isChecked() || m_optimizeCurve->isChecked() ); +} + +float VPencilOptionsWidget::fittingError() +{ + return m_fittingError->value(); +} + +void VPencilOptionsWidget::selectMode() +{ + m_widgetStack->raiseWidget( m_combo->currentItem() + 1 ); + + switch( m_combo->currentItem() ) + { + case 0: m_mode = VPencilTool::RAW; break; + case 1: m_mode = VPencilTool::CURVE; break; + case 2: m_mode = VPencilTool::STRAIGHT; break; + } +} + +int VPencilOptionsWidget::currentMode(){ + return m_mode; +} + +/* ------------------------------------------------------------------------------------------------------------------------*/ + +VPencilTool::VPencilTool( KarbonView *view ) + : VTool( view, "tool_pencil" ) +{ + m_Points.setAutoDelete( true ); + m_optionWidget = new VPencilOptionsWidget( view ); + registerTool( this ); + m_mode = CURVE; + m_optimize = true; + m_combineAngle = 3.0f; + m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) ); +} + +VPencilTool::~VPencilTool() +{ + delete m_cursor; +} + +QString +VPencilTool::contextHelp() +{ + QString s = i18n( "<qt><b>Pencil tool:</b><br>" ); + s += i18n( "- <i>Click</i> to begin drawing, release when you have finished."); + s += i18n( "- Press <i>Enter</i> or <i>double click</i> to end the polyline.</qt>" ); + + return s; +} + +void +VPencilTool::activate() +{ + VTool::activate(); + view()->statusMessage()->setText( i18n( "Pencil Tool" ) ); + view()->setCursor( *m_cursor ); + view()->part()->document().selection()->showHandle( false ); + + m_Points.clear(); + m_close = false; +} + +void +VPencilTool::deactivate() +{ + m_Points.removeLast(); + m_Points.removeLast(); + + VPath* line = 0L; + + QPtrList<KoPoint> complete; + QPtrList<KoPoint> *points = &m_Points; + + if( m_Points.count() > 1 ) + { + if( m_optimize || m_mode == STRAIGHT ) + { + complete.setAutoDelete( true ); + m_Points.setAutoDelete( false ); + + float cangle; + + if( m_mode == STRAIGHT ) + cangle = m_combineAngle; + else + cangle = 0.50f; + + #define ANGLE(P0,P1)\ + atan((P1)->y()-(P0)->y())/((P1)->x()-(P0)->x())*(180/M_PI) + + //Add the first point + complete.append( m_Points.first() ); + complete.append( m_Points.next() ); + + //Now we need to get the angle of the first line + float langle = ANGLE( complete.at( 0 ), complete.at( 1 ) ); + + KoPoint *nextp = NULL; + while( ( nextp = m_Points.next() ) ) + { + float angle = ANGLE( complete.last(), nextp ); + if( QABS( angle - langle ) < cangle ) + complete.removeLast(); + complete.append(nextp); + langle=angle; + } + m_Points.clear(); + m_Points.setAutoDelete(true); + + points = &complete; + } + + switch(m_mode) + { + case CURVE: + { + line = bezierFit( *points, m_optionWidget->fittingError() ); + break; + } + case STRAIGHT: + case RAW: + { + line = new VPath( 0L ); + KoPoint* p1 = (*points).first(); + KoPoint* plast = p1; + line->moveTo( *p1 ); + + KoPoint* pnext = 0L; + + while( ( pnext = (*points).next() ) ) + { + line->lineTo( *pnext ); + plast = pnext; + } + break; + } + } + + if( shiftPressed() ) + line->close(); + } + + if( line ) + { + VShapeCmd* cmd = new VShapeCmd( + &view()->part()->document(), + i18n( "Pencil" ), + line, + "14_pencil" ); + + view()->part()->addCommand( cmd, true ); + } +} + +void +VPencilTool::draw() +{ + VPainter* painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + m_mode = m_optionWidget->currentMode(); + m_optimize = m_optionWidget->optimize(); + m_combineAngle = m_optionWidget->combineAngle(); + + if( m_Points.count() > 1 ) + { + VPath line( 0L ); + line.moveTo( *m_Points.first() ); + + KoPoint *pnext; + while((pnext=m_Points.next())){ + line.lineTo( *pnext ); + } + + line.setState( VObject::edit ); + line.draw( painter, &line.boundingBox() ); + } + +} + + +void +VPencilTool::mouseMove() +{ +} + +void +VPencilTool::mouseButtonPress() +{ + m_Points.append( new KoPoint( last() ) ); + + draw(); +} + +void +VPencilTool::mouseButtonRelease() +{ + m_Points.append( new KoPoint( last() ) ); + draw(); + accept(); + return; +} + +void +VPencilTool::mouseButtonDblClick() +{ + accept(); +} + +void +VPencilTool::mouseDrag() +{ + if( m_Points.count() != 0 ) + { + draw(); + + m_Points.append( new KoPoint( last() ) ); + + draw(); + } +} + +void +VPencilTool::mouseDragRelease() +{ + mouseButtonRelease(); +} + +void +VPencilTool::mouseDragShiftPressed() +{ +} + +void +VPencilTool::mouseDragCtrlPressed() +{ + +} + +void +VPencilTool::mouseDragShiftReleased() +{ +} + +void +VPencilTool::mouseDragCtrlReleased() +{ +} + +void +VPencilTool::cancel() +{ + draw(); + + m_Points.clear(); +} + +void +VPencilTool::cancelStep() +{ + draw(); + + m_Points.clear(); + + draw(); +} + +void +VPencilTool::accept() +{ + deactivate(); + activate(); +} + +bool +VPencilTool::showDialog() const +{ + return m_optionWidget->exec() == QDialog::Accepted; +} + +void +VPencilTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Pencil Tool" ), "14_pencil", Qt::SHIFT+Qt::Key_P, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Pencil" ) ); + m_action->setExclusiveGroup( "freehand" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vpenciltool.h b/karbon/tools/vpenciltool.h new file mode 100644 index 00000000..d8eeb77a --- /dev/null +++ b/karbon/tools/vpenciltool.h @@ -0,0 +1,160 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __VPENCILTOOL_H__ +#define __VPENCILTOOL_H__ + + +#include <qptrlist.h> +#include <qstring.h> + +#include <klocale.h> +#include <kdialogbase.h> +#include "KoPoint.h" + +#include "vtool.h" + + +class QLabel; +class QWidget; +class VPath; +class KarbonView; +class QCheckBox; +class QWidgetStack; +class QComboBox; +class KDoubleNumInput; +class QCursor; + +class VPencilOptionsWidget : public KDialogBase +{ + Q_OBJECT + public: + VPencilOptionsWidget( KarbonView*view, QWidget* parent = 0L, const char* name = 0L ); + + int currentMode(); + bool optimize(); + float combineAngle(); + float fittingError(); + + public slots: + void selectMode(); + + private: + KarbonView *m_view; + QCheckBox *m_optimizeRaw; + QCheckBox *m_optimizeCurve; + KDoubleNumInput *m_combineAngle; + KDoubleNumInput *m_fittingError; + QWidgetStack *m_widgetStack; + QComboBox *m_combo; + int m_mode; +}; + + +/** + * The pencil tool. + * + * This tool has three modes of operation + * * Raw - exactly what is drawn by the user is what is captured + * * Straightend - captured data is straightended + * * Smooth - captured data is converted to a bezier curve + * + */ + +class VPencilTool : public VTool +{ + public: + VPencilTool( KarbonView *view ); + ~VPencilTool(); + + virtual void activate(); + virtual void deactivate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Pencil Tool" ); } + virtual QString contextHelp(); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + + virtual bool showDialog() const; + + enum { + RAW, + STRAIGHT, + CURVE + }; + + protected: + /** + * Helper method: draws the polyline. + */ + void draw(); + + virtual void mouseMove(); + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void mouseButtonDblClick(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + virtual void mouseDragShiftPressed(); + virtual void mouseDragCtrlPressed(); + virtual void mouseDragShiftReleased(); + virtual void mouseDragCtrlReleased(); + + virtual void cancel(); + virtual void cancelStep(); + virtual void accept(); + + /** + * The list of this polyline points. + */ + QPtrList<KoPoint> m_Points; + + /** + * The start of the last drawn vector. + */ + KoPoint m_lastVectorStart; + + /** + * The end of the last drawn vector. + */ + KoPoint m_lastVectorEnd; + + /** + * Indicates if the Line is to close. + */ + bool m_close; + + /** + * The mode of the pencile + */ + + short m_mode; + + bool m_optimize; + + float m_combineAngle; + + VPencilOptionsWidget *m_optionWidget; + + private: + QCursor* m_cursor; +}; + +#endif diff --git a/karbon/tools/vpolygontool.cc b/karbon/tools/vpolygontool.cc new file mode 100644 index 00000000..fcd0faeb --- /dev/null +++ b/karbon/tools/vpolygontool.cc @@ -0,0 +1,165 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qlabel.h> +#include <qgroupbox.h> + +#include <kdialogbase.h> +#include <klocale.h> +#include <KoUnitWidgets.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vstar.h> +#include "vpolygontool.h" + +VPolygonTool::VPolygonOptionsWidget::VPolygonOptionsWidget( KarbonView *view, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Polygon" ), Ok | Cancel ), m_view(view) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + new QLabel( i18n( "Radius:" ), group ); + m_radius = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 50.0, KoUnit::U_MM ); + refreshUnit(); + new QLabel( i18n( "Edges:" ), group ); + m_edges = new KIntSpinBox( group ); + m_edges->setMinValue( 3 ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + //setFixedSize( baseSize() ); +} + +double +VPolygonTool::VPolygonOptionsWidget::radius() const +{ + return m_radius->value(); +} + +uint +VPolygonTool::VPolygonOptionsWidget::edges() const +{ + return m_edges->value(); +} + +void +VPolygonTool::VPolygonOptionsWidget::setRadius( double value ) +{ + m_radius->changeValue( value ); +} + +void +VPolygonTool::VPolygonOptionsWidget::setEdges( uint value ) +{ + m_edges->setValue( value ); +} + +void +VPolygonTool::VPolygonOptionsWidget::refreshUnit() +{ + m_radius->setUnit( m_view->part()->unit() ); +} + +VPolygonTool::VPolygonTool( KarbonView *view ) + : VShapeTool( view, "tool_polygon", true ) +{ + // create config dialog: + m_optionsWidget = new VPolygonOptionsWidget( view ); + m_optionsWidget->setEdges( 5 ); + registerTool( this ); +} + +VPolygonTool::~VPolygonTool() +{ + delete( m_optionsWidget ); +} + +void +VPolygonTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +void +VPolygonTool::arrowKeyReleased( Qt::Key key ) +{ + int change = 0; + if( key == Qt::Key_Up ) + change = 1; + else if( key == Qt::Key_Down ) + change = -1; + + if( change != 0 ) + { + draw(); + + m_optionsWidget->setEdges( m_optionsWidget->edges() + change ); + + draw(); + } +} + +VPath* +VPolygonTool::shape( bool interactive ) const +{ + if( interactive ) + { + return + new VStar( + 0L, + m_p, + m_optionsWidget->radius(), + m_optionsWidget->radius(), + m_optionsWidget->edges(), 0, 0, 0, VStar::polygon ); + } + else + return + new VStar( + 0L, + m_p, + m_d1, m_d1, + m_optionsWidget->edges(), + m_d2, 0, 0, VStar::polygon ); +} + +bool +VPolygonTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VPolygonTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + KShortcut shortcut( Qt::Key_Plus ); + shortcut.append(KShortcut( Qt::Key_F9 ) ); + m_action = new KRadioAction( i18n( "Polygon Tool" ), "14_polygon", shortcut, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Polygon" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vpolygontool.h b/karbon/tools/vpolygontool.h new file mode 100644 index 00000000..028565db --- /dev/null +++ b/karbon/tools/vpolygontool.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VPOLYGONTOOL_H__ +#define __VPOLYGONTOOL_H__ + +#include <kdialogbase.h> + +#include "vshapetool.h" + +class KoUnitDoubleSpinBox; +class KIntSpinBox; + + +class VPolygonTool : public VShapeTool +{ +public: + VPolygonTool( KarbonView *view ); + virtual ~VPolygonTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Polygon Tool" ); } + + virtual VPath *shape( bool interactive = false ) const; + + void refreshUnit(); + + virtual void arrowKeyReleased( Qt::Key ); + +private: + class VPolygonOptionsWidget : public KDialogBase + { + public: + VPolygonOptionsWidget( KarbonView *view, QWidget *parent = 0L, const char *name = 0L ); + + double radius() const; + uint edges() const; + void setRadius( double value ); + void setEdges( uint value ); + + void refreshUnit(); + + private: + KoUnitDoubleSpinBox *m_radius; + KIntSpinBox *m_edges; + KarbonView *m_view; + }; + + VPolygonOptionsWidget* m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vpolylinetool.cc b/karbon/tools/vpolylinetool.cc new file mode 100644 index 00000000..59b72a0e --- /dev/null +++ b/karbon/tools/vpolylinetool.cc @@ -0,0 +1,504 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#include <qcursor.h> +#include <qevent.h> +#include <qlabel.h> + +#include <klocale.h> + +#include <karbon_part.h> +#include <karbon_view.h> +#include <core/vcolor.h> +#include <core/vcomposite.h> +#include <core/vfill.h> +#include <core/vstroke.h> +#include <core/vglobal.h> +#include <core/vcursor.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include "vpolylinetool.h" +#include <commands/vshapecmd.h> +#include <commands/vcommand.h> +#include <widgets/vcanvas.h> + +VPolylineTool::VPolylineTool( KarbonView *view ) + : VTool( view, "tool_polyline" ) +{ + m_bezierPoints.setAutoDelete( true ); + registerTool( this ); + m_crossCursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) ); +} + +VPolylineTool::~VPolylineTool() +{ + delete m_crossCursor; +} + +QString +VPolylineTool::contextHelp() +{ + QString s = i18n( "<qt><b>Polyline tool:</b><br>" ); + s += i18n( "- <i>Click</i> to add a node and <i>drag</i> to set its bezier vector.<br>" ); + s += i18n( "- Press <i>Ctrl</i> while dragging to edit the previous bezier vector.<br>" ); + s += i18n( "- Press <i>Shift</i> while dragging to change the curve in a straight line.<br>" ); + s += i18n( "- Press <i>Backspace</i> to cancel the last curve.<br>" ); + s += i18n( "- Press <i>Esc</i> to cancel the whole polyline.<br>" ); + s += i18n( "- Press <i>Enter</i> or <i>double click</i> to end the polyline.</qt>" ); + + return s; +} + +void +VPolylineTool::activate() +{ + VTool::activate(); + view()->statusMessage()->setText( i18n( "Polyline Tool" ) ); + view()->setCursor( *m_crossCursor ); + + m_bezierPoints.clear(); + m_close = false; + + connect( view()->part()->commandHistory(), SIGNAL(commandExecuted()), this, SLOT(commandExecuted()) ); +} + +void +VPolylineTool::initializePath( VPath &path ) +{ + KoPoint* p1 = m_bezierPoints.first(); + KoPoint* p2; + KoPoint* p3; + KoPoint* p4; + + path.moveTo( *p1 ); + + while( + ( p2 = m_bezierPoints.next() ) && + ( p3 = m_bezierPoints.next() ) && + ( p4 = m_bezierPoints.next() ) ) + { + if ( *p1 == *p2 ) + if ( *p3 == *p4 ) + path.lineTo( *p4 ); + else + //polyline->curve1To( *p3, *p4 ); + path.curveTo( *p3, *p4, *p4 ); + else + if ( *p3 == *p4 ) + //polyline->curve2To( *p2, *p4 ); + path.curveTo( *p2, *p2, *p4 ); + else + path.curveTo( *p2, *p3, *p4 ); + p1 = p4; + } +} + +void +VPolylineTool::createObject() +{ + VPath* polyline = 0L; + if( m_bezierPoints.count() > 2 ) + { + polyline = new VPath( 0L ); + if( polyline ) + { + initializePath( *polyline ); + if( m_close ) + polyline->close(); + + VShapeCmd* cmd = new VShapeCmd( + &view()->part()->document(), + i18n( "Polyline" ), + polyline, + "14_polyline" ); + + view()->part()->addCommand( cmd, true ); + } + } + + m_bezierPoints.clear(); + m_close = false; +} + +void +VPolylineTool::deactivate() +{ + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + + createObject(); + + disconnect( view()->part()->commandHistory(), SIGNAL(commandExecuted()), this, SLOT(commandExecuted()) ); +} + +void +VPolylineTool::draw() +{ + VPainter* painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + if( m_bezierPoints.count() > 2 ) + { + VPath polyline( 0L ); + initializePath( polyline ); + + polyline.setState( VObject::edit ); + polyline.draw( painter, &polyline.boundingBox() ); + } +} + +void +VPolylineTool::drawBezierVector( KoPoint& start, KoPoint& end ) +{ + VPainter* painter = view()->painterFactory()->editpainter(); + + painter->save(); + + float zoomFactor = view()->zoom(); + + painter->setRasterOp( Qt::NotROP ); + painter->newPath(); +/* VStroke stroke( Qt::blue, 0L, 1.0 ); + QValueList<float> array; + array << 2.0 << 3.0; + stroke.dashPattern().setArray( array );*/ + painter->setPen( Qt::DotLine /*stroke*/ ); + painter->setBrush( Qt::NoBrush ); + + painter->moveTo( start ); + painter->lineTo( end ); + painter->strokePath(); + painter->setRasterOp( Qt::XorROP ); + painter->newPath(); + painter->setPen( Qt::yellow ); + + float width = 2.0; + + painter->moveTo( KoPoint( + end.x() - width / zoomFactor, + end.y() - width / zoomFactor ) ); + painter->lineTo( KoPoint( + end.x() + width / zoomFactor, + end.y() - width / zoomFactor ) ); + painter->lineTo( KoPoint( + end.x() + width / zoomFactor, + end.y() + width / zoomFactor ) ); + painter->lineTo( KoPoint( + end.x() - width / zoomFactor, + end.y() + width / zoomFactor ) ); + painter->lineTo( KoPoint( + end.x() - width / zoomFactor, + end.y() - width / zoomFactor ) ); + + painter->strokePath(); + painter->restore(); +} + +void +VPolylineTool::mouseMove() +{ + if( m_bezierPoints.count() != 0 ) + { + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + draw(); + + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( _last ) ); + + draw(); + } +} + +void +VPolylineTool::mouseButtonPress() +{ + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + if( m_bezierPoints.count() != 0 ) + { + draw(); + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( _last ) ); + } + + m_lastVectorEnd = m_lastVectorStart = _last; + + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( _last ) ); + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + draw(); +} + +void +VPolylineTool::mouseButtonRelease() +{ + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + if( m_bezierPoints.count() == 2 ) + { + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( _last ) ); + + VPainter* painter = view()->painterFactory()->editpainter(); + painter->save(); + painter->setZoomFactor( view()->zoom() ); + painter->setRasterOp( Qt::XorROP ); + VStroke stroke( Qt::yellow, 0L, 1.0 ); + painter->setPen( stroke ); + painter->setBrush( Qt::yellow ); + painter->newPath(); + painter->drawNode( m_lastVectorStart, 2 ); + painter->strokePath(); + painter->restore(); + } + else + { + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + draw(); + m_bezierPoints.removeLast(); + KoPoint* p = new KoPoint( *m_bezierPoints.last() ); + m_bezierPoints.removeLast(); + KoPoint* b = new KoPoint( *m_bezierPoints.last() ); + m_bezierPoints.removeLast(); + + if( shiftPressed() ) + { + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( *m_bezierPoints.last() ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_lastVectorStart = m_lastVectorEnd = *p; + } + else if( ctrlPressed() ) + { + m_bezierPoints.removeLast(); + m_lastVectorStart = *m_bezierPoints.last(); + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( *b ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p - ( *b - *p ) ) ); + m_lastVectorEnd = _last; + } + else + { + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p - ( _last - *p ) ) ); + m_lastVectorStart = *p; + m_lastVectorEnd = _last; + } + if( m_bezierPoints.count() > 2 && p->isNear( *m_bezierPoints.first(), 3 ) ) + { + m_bezierPoints.append( new KoPoint( _last ) ); + m_close = true; + createObject(); + return; + } + } + + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( _last ) ); + + draw(); +} + +void +VPolylineTool::rightMouseButtonRelease() +{ + // end line without adding new points + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + + createObject(); +} + +void +VPolylineTool::mouseButtonDblClick() +{ + createObject(); +} + +void +VPolylineTool::mouseDrag() +{ + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + + if( m_bezierPoints.count() == 2 ) + { + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( _last ) ); + m_lastVectorEnd = _last; + + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + } + else + { + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + draw(); + + m_bezierPoints.removeLast(); + KoPoint* p = new KoPoint( *m_bezierPoints.last() ); + m_bezierPoints.removeLast(); + KoPoint* b = new KoPoint( *m_bezierPoints.last() ); + m_bezierPoints.removeLast(); + + if( shiftPressed() ) + { + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( *m_bezierPoints.last() ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_lastVectorStart = m_lastVectorEnd = *p; + } + else if( ctrlPressed() ) + { + m_bezierPoints.removeLast(); + m_lastVectorStart = *m_bezierPoints.last(); + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( *b ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p - ( *b - *p ) ) ); + m_lastVectorEnd = _last; + } + else + { + m_bezierPoints.append( new KoPoint( _last ) ); + m_bezierPoints.append( new KoPoint( *p ) ); + m_bezierPoints.append( new KoPoint( *p - ( _last - *p ) ) ); + m_lastVectorStart = *p; + m_lastVectorEnd = _last; + } + + draw(); + drawBezierVector( m_lastVectorStart, m_lastVectorEnd ); + } +} + +void +VPolylineTool::mouseDragRelease() +{ + mouseButtonRelease(); +} + +void +VPolylineTool::mouseDragShiftPressed() +{ +} + +void +VPolylineTool::mouseDragCtrlPressed() +{ + // Moves the mouse to the other bezier vector position. + if( m_bezierPoints.count() > 3 ) + { + KoPoint p; + p = *m_bezierPoints.at( m_bezierPoints.count() - 4) - *m_bezierPoints.at( m_bezierPoints.count() - 3 ); + + view()->setPos( p ); + } +} + +void +VPolylineTool::mouseDragShiftReleased() +{ +} + +void +VPolylineTool::mouseDragCtrlReleased() +{ + if( m_bezierPoints.count() > 3 ) + { + KoPoint p; + p = *m_bezierPoints.at( m_bezierPoints.count() - 3) - *m_bezierPoints.at( m_bezierPoints.count() - 4 ); + + view()->setPos( p ); + } +} + +void +VPolylineTool::cancel() +{ + draw(); + + m_bezierPoints.clear(); +} + +void +VPolylineTool::cancelStep() +{ + draw(); + + if ( m_bezierPoints.count() > 6 ) + { + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + KoPoint p1 = *m_bezierPoints.last(); + m_bezierPoints.removeLast(); + m_bezierPoints.removeLast(); + m_bezierPoints.append( new KoPoint( p1 ) ); + m_bezierPoints.append( new KoPoint( p1 ) ); + + view()->setPos( p1 ); + } + else + { + m_bezierPoints.clear(); + } + + draw(); +} + +void +VPolylineTool::accept() +{ + activate(); +} + +void +VPolylineTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + KShortcut shortcut( Qt::Key_Plus ); + shortcut.append( KShortcut( Qt::Key_F9 ) ); + m_action = new KRadioAction( i18n( "Polyline Tool" ), "14_polyline", shortcut, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Polyline" ) ); + m_action->setExclusiveGroup( "freehand" ); + //m_ownAction = true; + } +} + +void +VPolylineTool::commandExecuted() +{ + cancel(); +} + +#include "vpolylinetool.moc" diff --git a/karbon/tools/vpolylinetool.h b/karbon/tools/vpolylinetool.h new file mode 100644 index 00000000..83e4a562 --- /dev/null +++ b/karbon/tools/vpolylinetool.h @@ -0,0 +1,129 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + +*/ + +#ifndef __VPOLYLINETOOL_H__ +#define __VPOLYLINETOOL_H__ + + +#include <qptrlist.h> +#include <qstring.h> + +#include "KoPoint.h" + +#include "vtool.h" + + +class QLabel; +class QWidget; +class VPath; +class QCursor; + +/** + * The polyline tool. + * + * When the tool is activated, you draw your polyline until the tool is + * deactivated. + * When the mouse button is pressed, you add a Bezier node and sets the vector by + * dragging it. + * While dragging, when you press on CTRL, you edit the other vector, and when + * you press on SHIFT the current segment, the segment becames a line. + */ + +class VPolylineTool : public VTool +{ + Q_OBJECT + + public: + VPolylineTool( KarbonView *view ); + ~VPolylineTool(); + + virtual void setup(KActionCollection *collection); + virtual void activate(); + virtual void deactivate(); + + virtual QString uiname() { return i18n( "Polyline Tool" ); } + virtual QString contextHelp(); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + + protected: + /** + * Helper method: draws the polyline. + */ + void draw(); + + /** + * Helper method: draws a bezier vector. + */ + void drawBezierVector( KoPoint& start, KoPoint& end ); + + /** + * Creates the polyline from the bezier points. + */ + void createObject(); + + /** + * Initializes the specified path with the actual bezier points. + */ + void initializePath( VPath &path ); + + virtual void mouseMove(); + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void rightMouseButtonRelease(); + virtual void mouseButtonDblClick(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + virtual void mouseDragShiftPressed(); + virtual void mouseDragCtrlPressed(); + virtual void mouseDragShiftReleased(); + virtual void mouseDragCtrlReleased(); + + virtual void cancel(); + virtual void cancelStep(); + virtual void accept(); + + /** + * The list of this polyline points. + */ + QPtrList<KoPoint> m_bezierPoints; + + /** + * The start of the last drawn vector. + */ + KoPoint m_lastVectorStart; + + /** + * The end of the last drawn vector. + */ + KoPoint m_lastVectorEnd; + + /** + * Indicates if the polyline is to close. + */ + bool m_close; + protected slots: + void commandExecuted(); + + private: + QCursor* m_crossCursor; +}; + +#endif + diff --git a/karbon/tools/vrectangletool.cc b/karbon/tools/vrectangletool.cc new file mode 100644 index 00000000..e65f3e88 --- /dev/null +++ b/karbon/tools/vrectangletool.cc @@ -0,0 +1,143 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qgroupbox.h> + +#include <klocale.h> +#include <knuminput.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vrectangle.h> +#include "vrectangletool.h" +#include <KoUnitWidgets.h> + + +VRectangleTool::VRectangleOptionsWidget::VRectangleOptionsWidget( KarbonPart *part, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Rectangle" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + // add width/height-input: + m_widthLabel = new QLabel( i18n( "object width", "Width:" ), group ); + m_width = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + + m_heightLabel = new QLabel( i18n( "Height:" ), group ); + m_height = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + + refreshUnit(); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + //setFixedSize( baseSize() ); +} + +double +VRectangleTool::VRectangleOptionsWidget::width() const +{ + return m_width->value(); +} + +double +VRectangleTool::VRectangleOptionsWidget::height() const +{ + return m_height->value(); +} + +void +VRectangleTool::VRectangleOptionsWidget::setWidth( double value ) +{ + m_width->setValue( value ); +} + +void +VRectangleTool::VRectangleOptionsWidget::setHeight( double value ) +{ + m_height->setValue( value ); +} + +void +VRectangleTool::VRectangleOptionsWidget::refreshUnit() +{ + m_width->setUnit( m_part->unit() ); + m_height->setUnit( m_part->unit() ); +} + +VRectangleTool::VRectangleTool( KarbonView *view ) + : VShapeTool( view, "tool_rectangle" ) +{ + // Create config dialog: + m_optionWidget = new VRectangleOptionsWidget( view->part() ); + registerTool( this ); +} + +VRectangleTool::~VRectangleTool() +{ + delete( m_optionWidget ); +} + +void +VRectangleTool::refreshUnit() +{ + m_optionWidget->refreshUnit(); +} + +VPath * +VRectangleTool::shape( bool interactive ) const +{ + if( interactive ) + { + return + new VRectangle( + 0L, + m_p, + m_optionWidget->width(), + m_optionWidget->height() ); + } + else + return + new VRectangle( + 0L, + m_p, + m_d1, + m_d2 ); +} + +bool +VRectangleTool::showDialog() const +{ + return m_optionWidget->exec() == QDialog::Accepted; +} + +void +VRectangleTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Rectangle Tool" ), "14_rectangle", Qt::Key_Plus+Qt::Key_F9, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Rectangle" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vrectangletool.h b/karbon/tools/vrectangletool.h new file mode 100644 index 00000000..d5e45c30 --- /dev/null +++ b/karbon/tools/vrectangletool.h @@ -0,0 +1,70 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VRECTANGLETOOL_H__ +#define __VRECTANGLETOOL_H__ + + +#include <klocale.h> +#include <kdialogbase.h> + +#include "vshapetool.h" + +class KarbonView; +class QLabel; +class KoUnitDoubleSpinBox; + +class VRectangleTool : public VShapeTool +{ +public: + VRectangleTool( KarbonView *view ); + virtual ~VRectangleTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Rectangle Tool" ); } + virtual VPath* shape( bool interactive = false ) const; + + void refreshUnit(); + +private: + class VRectangleOptionsWidget : public KDialogBase + { + public: + VRectangleOptionsWidget( KarbonPart *part, QWidget* parent = 0L, const char* name = 0L ); + + double width() const; + double height() const; + void setWidth( double value ); + void setHeight( double value ); + void refreshUnit(); + + private: + KoUnitDoubleSpinBox *m_width; + KoUnitDoubleSpinBox *m_height; + KarbonPart *m_part; + QLabel *m_heightLabel; + QLabel *m_widthLabel; + }; + + VRectangleOptionsWidget *m_optionWidget; +}; + +#endif + diff --git a/karbon/tools/vrotatetool.cc b/karbon/tools/vrotatetool.cc new file mode 100644 index 00000000..987a7b60 --- /dev/null +++ b/karbon/tools/vrotatetool.cc @@ -0,0 +1,175 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <qcursor.h> +#include <qlabel.h> + +#include <klocale.h> +#include <KoRect.h> + +#include <karbon_part.h> +#include <karbon_view.h> +#include <core/vglobal.h> +#include "vrotatetool.h" +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <commands/vtransformcmd.h> + +#include <kdebug.h> + +VRotateTool::VRotateTool( KarbonView *view ) + : VTool( view, "tool_rotate" ) +{ + m_objects.setAutoDelete( true ); + registerTool( this ); +} + +VRotateTool::~VRotateTool() +{ + m_objects.clear(); +} + +void +VRotateTool::activate() +{ + view()->setCursor( QCursor( Qt::arrowCursor ) ); + view()->part()->document().selection()->setState( VObject::selected ); + view()->part()->document().selection()->showHandle( false ); + VTool::activate(); +} + +QString +VRotateTool::statusText() +{ + return i18n( "Rotate" ); +} + +void +VRotateTool::draw() +{ + VPainter* painter = view()->painterFactory()->editpainter(); + //painter->setZoomFactor( view()->zoom() ); + painter->setRasterOp( Qt::NotROP ); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + { + itr.current()->draw( painter, &itr.current()->boundingBox() ); + } +} + +void +VRotateTool::mouseButtonPress() +{ + //view()->painterFactory()->painter()->end(); + + recalc(); + + // Draw new object: + draw(); +} + +void +VRotateTool::mouseDrag() +{ + // Erase old object: + draw(); + + recalc(); + + // Draw new object: + draw(); +} + +void +VRotateTool::mouseDragRelease() +{ + view()->part()->addCommand( + new VRotateCmd( + &view()->part()->document(), + m_center, + m_angle, altPressed() ), + true ); +} + +void +VRotateTool::cancel() +{ + // Erase old object: + if ( isDragging() ) + { + draw(); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VRotateTool::recalc() +{ + // Get center: + m_center = view()->part()->document().selection()->boundingBox().center(); + + // Calculate angle between vector (last - center) and (first - center): + m_angle = VGlobal::one_pi_180 * ( + atan2( + last().y() - m_center.y(), + last().x() - m_center.x() ) + - + atan2( + first().y() - m_center.y(), + first().x() - m_center.x() ) ); + + VRotateCmd cmd( 0L, m_center, m_angle ); + + // Copy selected objects and transform: + m_objects.clear(); + VObject* copy; + + VObjectListIterator itr = view()->part()->document().selection()->objects(); + for ( ; itr.current() ; ++itr ) + { + if( itr.current()->state() != VObject::deleted ) + { + copy = itr.current()->clone(); + + cmd.visit( *copy ); + + copy->setState( VObject::edit ); + + m_objects.append( copy ); + } + } +} + +void +VRotateTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Rotate Tool" ), "14_rotate", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Rotate" ) ); + m_action->setExclusiveGroup( "manipulation" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vrotatetool.h b/karbon/tools/vrotatetool.h new file mode 100644 index 00000000..46e2c98b --- /dev/null +++ b/karbon/tools/vrotatetool.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VROTATETOOL_H__ +#define __VROTATETOOL_H__ + +#include "vselection.h" +#include "vtool.h" + + +class VRotateTool : public VTool +{ +public: + VRotateTool( KarbonView *view ); + virtual ~VRotateTool(); + + virtual void activate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Rotate Tool" ); } + virtual enumToolType toolType() { return TOOL_MANIPULATION; } + virtual QString statusText(); + virtual uint priority() { return 0; } + +protected: + virtual void draw(); + + virtual void mouseButtonPress(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + + virtual void cancel(); + +private: + void recalc(); + + KoPoint m_center; + double m_angle; + + VHandleNode m_activeNode; + + // A list of temporary objects: + VObjectList m_objects; +}; + +#endif + diff --git a/karbon/tools/vroundrecttool.cc b/karbon/tools/vroundrecttool.cc new file mode 100644 index 00000000..af21d4d9 --- /dev/null +++ b/karbon/tools/vroundrecttool.cc @@ -0,0 +1,179 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qgroupbox.h> +#include <qlabel.h> + +#include <knuminput.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vrectangle.h> +#include "vroundrecttool.h" +#include "KoUnitWidgets.h" + +#include <kgenericfactory.h> + +VRoundRectTool::VRoundRectOptionsWidget::VRoundRectOptionsWidget( KarbonPart *part, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Round Rect" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + new QLabel( i18n( "object width", "Width:" ), group ); + + KoUnit::Unit unit = KoUnit::U_CM; + m_width = new KoUnitDoubleSpinBox( group, 0.0, KoUnit::fromUserValue( 1000.0, unit ), KoUnit::fromUserValue( 0.5, unit ), KoUnit::fromUserValue( 10.0, unit ), unit ); + + new QLabel( i18n( "Height (%1):" ).arg(KoUnit::unitName( m_part->unit() )), group ); + m_height = new KoUnitDoubleSpinBox( group, 0.0, KoUnit::fromUserValue( 1000.0, unit ), KoUnit::fromUserValue( 0.5, unit ), KoUnit::fromUserValue( 10.0, unit ), unit ); + + new QLabel( i18n( "Edge radius X:" ), group ); + m_roundx = new KoUnitDoubleSpinBox( group, 0.0, KoUnit::fromUserValue( 100.0, unit ), KoUnit::fromUserValue( 0.1, unit ), KoUnit::fromUserValue( 1.0, unit ), unit ); + + new QLabel( i18n( "Edge radius Y:" ), group ); + m_roundy = new KoUnitDoubleSpinBox( group, 0.0, KoUnit::fromUserValue( 100.0, unit ), KoUnit::fromUserValue( 0.1, unit ), KoUnit::fromUserValue( 1.0, unit ), unit ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +double +VRoundRectTool::VRoundRectOptionsWidget::width() const +{ + return m_width->value(); +} + +double +VRoundRectTool::VRoundRectOptionsWidget::height() const +{ + return m_height->value(); +} + +double +VRoundRectTool::VRoundRectOptionsWidget::roundx() const +{ + return m_roundx->value(); +} + +double +VRoundRectTool::VRoundRectOptionsWidget::roundy() const +{ + return m_roundy->value(); +} + +void +VRoundRectTool::VRoundRectOptionsWidget::setWidth( double value ) +{ + m_width->changeValue( value ); +} + +void +VRoundRectTool::VRoundRectOptionsWidget::setHeight( double value ) +{ + m_height->changeValue( value ); +} + +void +VRoundRectTool::VRoundRectOptionsWidget::setRoundX( double value ) +{ + m_roundx->changeValue( value ); +} + +void +VRoundRectTool::VRoundRectOptionsWidget::setRoundY( double value ) +{ + m_roundy->changeValue( value ); +} + +void +VRoundRectTool::VRoundRectOptionsWidget::refreshUnit () +{ + m_width->setUnit( m_part->unit() ); + m_height->setUnit( m_part->unit() ); + m_roundx->setUnit( m_part->unit() ); + m_roundy->setUnit( m_part->unit() ); +} + +VRoundRectTool::VRoundRectTool( KarbonView *view ) + : VShapeTool( view, "tool_round_rectangle" ) +{ + // Create config dialog: + m_optionsWidget = new VRoundRectOptionsWidget( view->part() ); + registerTool( this ); +} + +VRoundRectTool::~VRoundRectTool() +{ + delete( m_optionsWidget ); +} + +void VRoundRectTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +VPath* +VRoundRectTool::shape( bool interactive ) const +{ + if( interactive ) + { + return + new VRectangle( + 0L, + m_p, + m_optionsWidget->width(), + m_optionsWidget->height(), + m_optionsWidget->roundx(), + m_optionsWidget->roundy() ); + } + else { + return + new VRectangle( + 0L, + m_p, + m_d1, + m_d2, + m_optionsWidget->roundx(), + m_optionsWidget->roundy() ); + } +} + +bool +VRoundRectTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VRoundRectTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Round Rectangle Tool" ), "14_roundrect", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Round Rectangle" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vroundrecttool.h b/karbon/tools/vroundrecttool.h new file mode 100644 index 00000000..75e86796 --- /dev/null +++ b/karbon/tools/vroundrecttool.h @@ -0,0 +1,81 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VROUNDRECTTOOL_H__ +#define __VROUNDRECTTOOL_H__ + +#include <klocale.h> +#include <kdialogbase.h> +#include <knuminput.h> + + +#include "vshapetool.h" + +class KarbonView; +class KarbonPart; +class QLabel; +class KoUnitDoubleSpinBox; + + +class VRoundRectTool : public VShapeTool +{ +public: + VRoundRectTool( KarbonView *view ); + virtual ~VRoundRectTool(); + + virtual bool showDialog() const; + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Round Rectangle Tool" ); } + + virtual VPath* shape( bool interactive = false ) const; + + void refreshUnit(); + +private: + class VRoundRectOptionsWidget : public KDialogBase + { + public: + VRoundRectOptionsWidget( KarbonPart *part, QWidget *parent = 0L, const char *name = 0L ); + + double width() const; + double height() const; + double roundx() const; + double roundy() const; + void setWidth( double value ); + void setHeight( double value ); + void setRoundX( double value ); + void setRoundY( double value ); + void refreshUnit (); + + private: + + KoUnitDoubleSpinBox* m_width; + KoUnitDoubleSpinBox* m_height; + KoUnitDoubleSpinBox* m_roundx; + KoUnitDoubleSpinBox* m_roundy; + + KarbonPart* m_part; + + }; + + VRoundRectOptionsWidget* m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vselectnodestool.cc b/karbon/tools/vselectnodestool.cc new file mode 100644 index 00000000..1c628faa --- /dev/null +++ b/karbon/tools/vselectnodestool.cc @@ -0,0 +1,443 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <qcursor.h> +#include <qlabel.h> + +#include <klocale.h> +#include <KoPoint.h> +#include <KoRect.h> + +#include <karbon_part.h> +#include <karbon_view.h> + +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <visitors/vselectnodes.h> +#include <commands/vtransformcmd.h> +#include <visitors/vdrawselection.h> +#include <core/vselection.h> +#include <core/vcursor.h> +#include "vselectnodestool.h" +#include <vtransformnodes.h> +#include <commands/vdeletenodescmd.h> +#include <widgets/vcanvas.h> + +#include <kdebug.h> + +VSelectNodesTool::VSelectNodesTool( KarbonView* view ) + : VTool( view, "tool_select_nodes" ), m_state( normal ), m_select( true ) +{ + registerTool( this ); +} + +VSelectNodesTool::~VSelectNodesTool() +{ +} + +void +VSelectNodesTool::activate() +{ + if( view() ) + { + view()->setCursor( VCursor::needleArrow() ); + view()->part()->document().selection()->showHandle( false ); + view()->part()->document().selection()->setSelectObjects( false ); + // deselect all nodes + view()->part()->document().selection()->selectNodes( false ); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } + VTool::activate(); +} + +QString +VSelectNodesTool::statusText() +{ + if( m_state == normal ) + return i18n( "Editing Nodes" ); + else + return QString( "" ); +} + +void +VSelectNodesTool::draw() +{ + VPainter *painter = view()->painterFactory()->editpainter(); + painter->setZoomFactor( view()->zoom() ); + painter->setRasterOp( Qt::NotROP ); + + if( m_state == dragging ) + { + painter->setPen( Qt::DotLine ); + painter->newPath(); + painter->moveTo( KoPoint( m_first.x(), m_first.y() ) ); + painter->lineTo( KoPoint( m_current.x(), m_first.y() ) ); + painter->lineTo( KoPoint( m_current.x(), m_current.y() ) ); + painter->lineTo( KoPoint( m_first.x(), m_current.y() ) ); + painter->lineTo( KoPoint( m_first.x(), m_first.y() ) ); + painter->strokePath(); + } + else + { + VDrawSelection op( m_objects, painter, true, VSelection::handleSize() ); + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + op.visit( *( itr.current() ) ); + } +} + +void +VSelectNodesTool::setCursor() const +{ + if( m_state >= moving ) + { + view()->setCursor( VCursor::needleMoveArrow() ); + return; + } + + KoRect selrect = calcSelRect( last() ); + + QPtrList<VSegment> segments = view()->part()->document().selection()->getSegments( selrect ); + if( segments.count() > 0 ) + { + VSegment* seg = segments.at( 0 ); + for( int i = 0; i < seg->degree(); ++i ) + if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) ) + { + view()->setCursor( VCursor::needleMoveArrow() ); + break; + } + } + else + view()->setCursor( VCursor::needleArrow() ); +} + +void +VSelectNodesTool::mouseButtonPress() +{ + m_first = m_current = first(); + + m_state = normal; + m_select = true; + + recalc(); + + view()->part()->document().selection()->setState( VObject::edit ); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + view()->part()->document().selection()->setState( VObject::selected ); + + VSelection* selection = view()->part()->document().selection(); + + KoRect selrect = calcSelRect( m_current ); + + // get segments with control points inside selection rect + QPtrList<VSegment> segments = selection->getSegments( selrect ); + if( segments.count() > 0 ) + { + VSegment *seg = segments.at( 0 ); + VSegment* prev = seg->prev(); + VSegment* next = seg->next(); + + // allow moving bezier points only if one of the bezier points is within the selection rect + // and no neighboring knot is selected + if( segments.count() == 1 && ! selrect.contains( seg->knot() ) && ! seg->knotIsSelected() + && ( prev && ! prev->knotIsSelected() ) ) + { + if( selrect.contains( seg->point( 1 ) ) ) + { + m_state = movingbezier1; + if( next ) + next->selectPoint( 0, false ); + } + else if( selrect.contains( seg->point( 0 ) ) ) + { + m_state = movingbezier2; + if( prev ) + prev->selectPoint( 1, false ); + } + } + else + { + for( VSegment *seg = segments.first(); seg; seg = segments.next() ) + { + for( int i = 0; i < seg->degree(); ++i ) + { + if( seg->pointIsSelected( i ) && selrect.contains( seg->point( i ) ) ) + { + m_state = moving; + break; + } + } + if( m_state == moving ) + break; + } + } + + double minDist = -1.0; + // use the nearest control point of all the segments as starting point + for( VSegment *seg = segments.first(); seg; seg = segments.next() ) + { + for( int i = 0; i < seg->degree(); ++i ) + { + if( selrect.contains( seg->point( i ) ) ) + { + KoPoint vDist = seg->point( i ) - m_current; + double dist = vDist.x()*vDist.x() + vDist.y()*vDist.y(); + if( minDist < 0.0 || dist < minDist ) + { + m_first = seg->point( i ); + minDist = dist; + } + } + } + } + recalc(); + } + else + m_state = dragging; + + draw(); +} + +void +VSelectNodesTool::rightMouseButtonPress() +{ + m_first = m_current = first(); + + m_state = normal; + m_select = false; + + recalc(); + + view()->part()->document().selection()->setState( VObject::edit ); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + view()->part()->document().selection()->setState( VObject::selected ); + + draw(); +} + +bool +VSelectNodesTool::keyReleased( Qt::Key key ) +{ + VSelection* selection = view()->part()->document().selection(); + + switch( key ) + { + // increase/decrease the handle size + case Qt::Key_I: + { + uint handleSize = selection->handleSize(); + if( shiftPressed() ) + selection->setHandleSize( ++handleSize ); + else if( handleSize > 1 ) + selection->setHandleSize( --handleSize ); + } + break; + case Qt::Key_Delete: + if( selection->objects().count() > 0 ) + view()->part()->addCommand( new VDeleteNodeCmd( &view()->part()->document() ), true ); + break; + default: return false; + } + + if( view() ) + view()->repaintAll( selection->boundingBox() ); + + return true; +} + +void +VSelectNodesTool::mouseButtonRelease() +{ + // erase old object: + draw(); + + VSelection* selection = view()->part()->document().selection(); + + KoRect selrect = calcSelRect( last() ); + + if( ctrlPressed() ) + selection->append( selrect.normalize(), false, false ); + else + selection->append( selrect.normalize(), false, true ); + + view()->selectionChanged(); + view()->part()->repaintAllViews(); + m_state = normal; +} + +void +VSelectNodesTool::rightMouseButtonRelease() +{ + // erase old object: + draw(); + + VSelection* selection = view()->part()->document().selection(); + + KoRect selrect = calcSelRect( last() ); + + selection->take( selrect.normalize(), false, false ); + + view()->selectionChanged(); + view()->part()->repaintAllViews(); + m_state = normal; +} + +void +VSelectNodesTool::mouseDrag() +{ + draw(); + + recalc(); + + draw(); +} + +void +VSelectNodesTool::mouseDragRelease() +{ + if( m_state >= moving ) + { + view()->part()->document().selection()->setState( VObject::selected ); + VCommand *cmd; + QPtrList<VSegment> segments; + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + if( m_state == movingbezier1 || m_state == movingbezier2 ) + { + KoRect selrect = calcSelRect( m_first ); + segments = view()->part()->document().selection()->getSegments( selrect ); + cmd = new VTranslateBezierCmd( &view()->part()->document(), segments.at( 0 ), + qRound( ( _last.x() - m_first.x() ) ), + qRound( ( _last.y() - m_first.y() ) ), + m_state == movingbezier2 ); + } + else + { + cmd = new VTranslatePointCmd( + &view()->part()->document(), + qRound( ( _last.x() - m_first.x() ) ), + qRound( ( _last.y() - m_first.y() ) ) ); + } + view()->part()->addCommand( cmd, true ); + m_state = normal; + } + else + { + KoPoint fp = m_first; + KoPoint lp = last(); + + if ( (fabs(lp.x() - fp.x()) + fabs(lp.y()-fp.y())) < 3.0 ) + { + // AK - should take the middle point here + fp = last() - KoPoint(8.0, 8.0); + lp = last() + KoPoint(8.0, 8.0); + } + + // erase old object: + draw(); + + if( m_select ) + { + view()->part()->document().selection()->append(); // select all + view()->part()->document().selection()->append( + KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(), + false, true ); + } + else + { + view()->part()->document().selection()->take( + KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(), + false, false ); + } + view()->selectionChanged(); + view()->part()->repaintAllViews(); + m_state = normal; + } +} + +void +VSelectNodesTool::cancel() +{ + // Erase old object: + if ( isDragging() ) + { + draw(); + m_state = normal; + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VSelectNodesTool::recalc() +{ + if( m_state == dragging ) + { + m_current = last(); + } + else if( m_state == moving || m_state == movingbezier1 || m_state == movingbezier2 ) + { + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + double distx = _last.x() - m_first.x(); + double disty = _last.y() - m_first.y(); + // move operation + QWMatrix mat; + mat.translate( distx, disty ); + + // Copy selected objects and transform: + m_objects.clear(); + VObject* copy; + + VTransformNodes op( mat ); + + VObjectListIterator itr = view()->part()->document().selection()->objects(); + for ( ; itr.current() ; ++itr ) + { + if( itr.current()->state() != VObject::deleted ) + { + copy = itr.current()->clone(); + copy->setState( VObject::edit ); + op.visit( *copy ); + m_objects.append( copy ); + } + } + } +} + +void +VSelectNodesTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Select Nodes Tool" ), "14_selectnodes", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Select Nodes" ) ); + m_action->setExclusiveGroup( "select" ); + //m_ownAction = true; + } +} + +KoRect +VSelectNodesTool::calcSelRect( const KoPoint &pos ) const +{ + double tolerance = view()->part()->document().selection()->handleSize() / view()->zoom(); + return KoRect( pos.x() - tolerance, pos.y() - tolerance, 2 * tolerance + 1.0, 2 * tolerance + 1.0 ); +} diff --git a/karbon/tools/vselectnodestool.h b/karbon/tools/vselectnodestool.h new file mode 100644 index 00000000..d0a5b296 --- /dev/null +++ b/karbon/tools/vselectnodestool.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTNODESTOOL_H__ +#define __VSELECTNODESTOOL_H__ + +#include "vtool.h" + +class VSelectNodesTool : public VTool +{ +public: + VSelectNodesTool( KarbonView *view ); + virtual ~VSelectNodesTool(); + + virtual void activate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Select Nodes Tool" ); } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual QString statusText(); + virtual uint priority() { return 1; } + +protected: + virtual void draw(); + + virtual void setCursor() const; + + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void mouseDragRelease(); + virtual void mouseDrag(); + virtual void rightMouseButtonPress(); + virtual void rightMouseButtonRelease(); + + virtual bool keyReleased( Qt::Key ); + + virtual void cancel(); + +private: + enum { normal, dragging, moving, movingbezier1, movingbezier2 } m_state; + + void recalc(); + + KoRect calcSelRect( const KoPoint &pos ) const; + + // A list of temporary objects: + VObjectList m_objects; + + KoPoint m_current; + KoPoint m_first; + + bool m_select; +}; + +#endif + diff --git a/karbon/tools/vselecttool.cc b/karbon/tools/vselecttool.cc new file mode 100644 index 00000000..19338038 --- /dev/null +++ b/karbon/tools/vselecttool.cc @@ -0,0 +1,613 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> +#include <stdlib.h> + +#include <qcursor.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> + +#include <KoPoint.h> +#include <KoRect.h> +#include <kdebug.h> + +#include <karbon_part.h> +#include <karbon_view.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <core/vselection.h> +#include "vselecttool.h" +#include <commands/vtransformcmd.h> +#include <visitors/vselectiondesc.h> +#include <visitors/vselectobjects.h> +#include <widgets/vcanvas.h> + +VSelectOptionsWidget::VSelectOptionsWidget( KarbonPart *part ) + : KDialogBase( 0L, "", true, i18n( "Selection" ), Ok | Cancel ), m_part( part ) +{ + QButtonGroup *group = new QButtonGroup( 1, Qt::Horizontal, i18n( "Selection Mode" ), this ); + + new QRadioButton( i18n( "Select in current layer" ), group ); + new QRadioButton( i18n( "Select in visible layers" ), group ); + new QRadioButton( i18n( "Select in selected layers" ), group ); + + group->setRadioButtonExclusive( true ); + group->setButton( part->document().selectionMode() ); + + connect( group, SIGNAL( clicked( int ) ), this, SLOT( modeChange( int ) ) ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} // VSelectOptionsWidget::VSelectOptionsWidget + +void VSelectOptionsWidget::modeChange( int mode ) +{ + m_part->document().setSelectionMode( (VDocument::VSelectionMode)mode ); +} // VSelectOptionsWidget::modeChanged + +VSelectTool::VSelectTool( KarbonView *view ) + : VTool( view, "tool_select" ), m_state( normal ) +{ + m_lock = false; + m_add = true; + m_objects.setAutoDelete( true ); + m_optionsWidget = new VSelectOptionsWidget( view->part() ); + registerTool( this ); + connect( view, SIGNAL( selectionChange() ), this, SLOT( updateStatusBar() ) ); +} + +VSelectTool::~VSelectTool() +{ + delete m_optionsWidget; +} + +void +VSelectTool::activate() +{ + VTool::activate(); + view()->setCursor( QCursor( Qt::arrowCursor ) ); + view()->part()->document().selection()->showHandle(); + view()->part()->document().selection()->setSelectObjects(); + view()->part()->document().selection()->setState( VObject::selected ); + view()->part()->document().selection()->selectNodes(); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + updateStatusBar(); +} + +QString +VSelectTool::statusText() +{ + return i18n( "Select" ); +} + +QString VSelectTool::contextHelp() +{ + QString s = i18n( "<qt><b>Selection tool:</b><br>" ); + s += i18n( "<i>Select in current layer:</i><br>The selection is made in the layer selected in the layers docker.<br><br>" ); + s += i18n( "<i>Select in visible layers:</i><br>The selection is made in the visible layers (eye in the layers docker).<br><br>" ); + s += i18n( "<i>Select in selected layers:</i><br>The selection is made in the checked layers in the layers docker.<br><br>" ); + s += i18n( "<i>Position using arrow keys</i><br>The selection can be positioned up, down, left and right using the corresponding arrow keys." ); + return s; +} // VSelectTool::contextHelp + +void +VSelectTool::draw() +{ + VPainter *painter = view()->painterFactory()->editpainter(); + //painter->setZoomFactor( view()->zoom() ); + painter->setRasterOp( Qt::NotROP ); + + KoRect rect = view()->part()->document().selection()->boundingBox(); + + if( m_state != normal ) + { + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + { + itr.current()->draw( painter, &itr.current()->boundingBox() ); + } + } + else if( m_state == normal ) + { + painter->setPen( Qt::DotLine ); + painter->newPath(); + painter->moveTo( KoPoint( first().x(), first().y() ) ); + painter->lineTo( KoPoint( m_current.x(), first().y() ) ); + painter->lineTo( KoPoint( m_current.x(), m_current.y() ) ); + painter->lineTo( KoPoint( first().x(), m_current.y() ) ); + painter->lineTo( KoPoint( first().x(), first().y() ) ); + painter->strokePath(); + + m_state = normal; + } +} + +void +VSelectTool::setCursor() const +{ + if( m_state != normal || !view() ) return; + switch( view()->part()->document().selection()->handleNode( last() ) ) + { + case node_lt: + case node_rb: + view()->setCursor( QCursor( Qt::SizeFDiagCursor ) ); + break; + case node_rt: + case node_lb: + view()->setCursor( QCursor( Qt::SizeBDiagCursor ) ); + break; + case node_lm: + case node_rm: + view()->setCursor( QCursor( Qt::SizeHorCursor ) ); + break; + case node_mt: + case node_mb: + view()->setCursor( QCursor( Qt::SizeVerCursor ) ); + break; + default: + view()->setCursor( QCursor( Qt::arrowCursor ) ); + } +} + +void +VSelectTool::mouseButtonPress() +{ + // we are adding to the selection + m_add = true; + + m_current = first(); + + m_activeNode = view()->part()->document().selection()->handleNode( first() ); + KoRect rect = view()->part()->document().selection()->boundingBox(); + + if( m_activeNode != node_none ) + m_state = scaling; + else if( rect.contains( m_current ) && m_state == normal ) + m_state = moving; + + recalc(); + + // undraw selection bounding box + view()->part()->document().selection()->setState( VObject::edit ); + view()->repaintAll( rect ); + view()->part()->document().selection()->setState( VObject::selected ); + + draw(); +} + +void +VSelectTool::rightMouseButtonPress() +{ + // we are removing from the selection + m_add = false; + + m_current = first(); + + recalc(); + + // undraw selection bounding box + view()->part()->document().selection()->setState( VObject::edit ); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + view()->part()->document().selection()->setState( VObject::selected ); + + draw(); +} + +void +VSelectTool::mouseDrag() +{ + draw(); + + recalc(); + + draw(); +} + +void +VSelectTool::rightMouseButtonRelease() +{ + m_state = normal; + m_add = true; + + if( ctrlPressed() ) + { + // unselect the topmost object under the mouse cursor + VObjectList newSelection; + VSelectObjects selector( newSelection, first() ); + if( selector.visit( view()->part()->document() ) ) + view()->part()->document().selection()->take( *newSelection.last() ); + + view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() ); + view()->selectionChanged(); + + updateStatusBar(); + } + else if( view()->part()->document().selection()->objects().count() > 0 ) + { + view()->showSelectionPopupMenu( QCursor::pos() ); + } +} + +void +VSelectTool::mouseButtonRelease() +{ + m_state = normal; + m_add = true; + + // selection of next underlying object + if( shiftPressed() ) + { + VObjectList newSelection; + VObjectList oldSelection = view()->part()->document().selection()->objects(); + + // clear selection if not in multi-slection-mode + if( ! ctrlPressed() ) + view()->part()->document().selection()->clear(); + + // get a list of all object under the mouse cursor + VSelectObjects selector( newSelection, first(), true, true ); + if( selector.visit( view()->part()->document() ) ) + { + // determine the last selected object of the object stack + VObject *lastMatched = 0L; + VObjectListIterator it( newSelection ); + for( ; it.current(); ++it ) + { + if( oldSelection.contains( it.current() ) ) + lastMatched = it.current(); + } + + // select the next underlying object or the first if: + // - none is selected + // - the stack's bottom object was the last selected object + if( lastMatched && lastMatched != newSelection.first() ) + view()->part()->document().selection()->append( newSelection.at( newSelection.find( lastMatched )-1 ) ); + else + view()->part()->document().selection()->append( newSelection.last() ); + } + } + else + { + // clear selection if not in multi-slection-mode + if( ! ctrlPressed() ) + view()->part()->document().selection()->clear(); + + // append the topmost object under the mouse cursor to the selection + VObjectList newSelection; + VSelectObjects selector( newSelection, first() ); + if( selector.visit( view()->part()->document() ) ) + view()->part()->document().selection()->append( newSelection.last() ); + } + + view()->part()->repaintAllViews( view()->part()->document().selection()->boundingBox() ); + view()->selectionChanged(); + + updateStatusBar(); +} + +void +VSelectTool::mouseDragRelease() +{ + if( m_state == normal ) + { + // Y mirroring + KoPoint fp = first(); + KoPoint lp = last(); + if( ! ctrlPressed() ) + view()->part()->document().selection()->clear(); + + KoRect selRect = KoRect( fp.x(), fp.y(), lp.x() - fp.x(), lp.y() - fp.y() ).normalize(); + if( m_add ) + view()->part()->document().selection()->append( selRect ); + else + view()->part()->document().selection()->take( selRect ); + view()->part()->repaintAllViews( selRect ); + } + else if( m_state == moving ) + { + m_state = normal; + recalc(); + if( m_lock ) + view()->part()->addCommand( + new VTranslateCmd( + &view()->part()->document(), + abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? qRound( m_distx ) : 0, + abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? qRound( m_disty ) : 0, altPressed() ), + true ); + else + view()->part()->addCommand( + new VTranslateCmd( &view()->part()->document(), qRound( m_distx ), qRound( m_disty ), altPressed() ), + true ); + } + else if( m_state == scaling ) + { + m_state = normal; + view()->part()->addCommand( + new VScaleCmd( &view()->part()->document(), m_sp, m_s1, m_s2, altPressed() ), + true ); + m_s1 = m_s2 = 1; + } + + view()->selectionChanged(); + m_lock = false; + updateStatusBar(); +} + +void +VSelectTool::arrowKeyReleased( Qt::Key key ) +{ + int dx = 0; + int dy = 0; + switch( key ) + { + case Qt::Key_Up: dy = 10; break; + case Qt::Key_Down: dy = -10; break; + case Qt::Key_Right: dx = 10; break; + case Qt::Key_Left: dx = -10; break; + default: return; + } + m_state = normal; + view()->part()->addCommand( + new VTranslateCmd( + &view()->part()->document(), + dx, dy ), + true ); + view()->selectionChanged(); + updateStatusBar(); +} + +bool +VSelectTool::keyReleased( Qt::Key key ) +{ + + VSelection* selection = view()->part()->document().selection(); + + switch( key ) + { + // increase/decrease the handle size + case Qt::Key_I: + { + uint handleSize = selection->handleSize(); + if( shiftPressed() ) + selection->setHandleSize( ++handleSize ); + else if( handleSize > 1 ) + selection->setHandleSize( --handleSize ); + } + break; + default: return false; + } + + if( view() ) + view()->repaintAll( selection->boundingBox() ); + + return true; +} + +void +VSelectTool::updateStatusBar() const +{ + if( ! view() ) + return; + + if( ! view()->part() ) + return; + + int objcount = view()->part()->document().selection()->objects().count(); + if( objcount > 0 ) + { + KoRect rect = view()->part()->document().selection()->boundingBox(); + + double x = KoUnit::toUserValue( rect.x(), view()->part()->unit() ); + double y = KoUnit::toUserValue( rect.y(), view()->part()->unit() ); + double r = KoUnit::toUserValue( rect.right(), view()->part()->unit() ); + double b = KoUnit::toUserValue( rect.bottom(), view()->part()->unit() ); + + // print bottom-left (%1,%2), top-right (%3,%4) corner of selection bounding box and document unit (%5) + QString selectMessage = i18n( "[(left,bottom), (right,top)] (actual unit)", "Selection [(%1, %2), (%3, %4)] (%5)").arg( x, 0, 'f', 1 ).arg( y, 0, 'f', 1 ).arg( r, 0, 'f', 1 ).arg( b, 0, 'f', 1 ).arg( view()->part()->unitName() ); + + VSelectionDescription selectionDesc; + selectionDesc.visit( *view()->part()->document().selection() ); + selectMessage += QString( "(%1)" ).arg( selectionDesc.description() ); + + view()->statusMessage()->setText( selectMessage ); + } + else + view()->statusMessage()->setText( i18n( "No selection" ) ); +} + +void +VSelectTool::mouseDragCtrlPressed() +{ + m_lock = true; +} + +void +VSelectTool::mouseDragCtrlReleased() +{ + m_lock = false; +} + +void +VSelectTool::mouseDragShiftPressed() +{ + draw(); + + recalc(); + + draw(); +} + +void +VSelectTool::mouseDragShiftReleased() +{ + draw(); + + recalc(); + + draw(); +} + +void +VSelectTool::cancel() +{ + // Erase old object: + if ( isDragging() ) + { + draw(); + m_state = normal; + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VSelectTool::recalc() +{ + if( m_state == normal ) + { + m_current = last(); + } + else + { + VTransformCmd* cmd; + KoPoint _first = view()->canvasWidget()->snapToGrid( first() ); + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + KoRect rect = view()->part()->document().selection()->boundingBox(); + + if( m_state == moving ) + { + KoPoint p( rect.x() + last().x() - first().x(), rect.bottom() + last().y() - first().y() ); + p = view()->canvasWidget()->snapToGrid( p ); + m_distx = p.x() - rect.x(); + m_disty = p.y() - rect.bottom(); + if( m_lock ) + cmd = new VTranslateCmd( 0L, abs( int( m_distx ) ) >= abs( int( m_disty ) ) ? m_distx : 0, + abs( int( m_distx ) ) <= abs( int( m_disty ) ) ? m_disty : 0 ); + else + cmd = new VTranslateCmd( 0L, m_distx, m_disty ); + } + else + { + if( m_activeNode == node_lb ) + { + m_sp = KoPoint( rect.right(), rect.bottom() ); + m_s1 = ( rect.right() - _last.x() ) / double( rect.width() ); + m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_mb ) + { + m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.bottom() ); + m_s1 = 1; + m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_rb ) + { + m_sp = KoPoint( rect.x(), rect.bottom() ); + m_s1 = ( _last.x() - rect.x() ) / double( rect.width() ); + m_s2 = ( rect.bottom() - _last.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_rm) + { + m_sp = KoPoint( rect.x(), ( rect.bottom() + rect.top() ) / 2 ); + m_s1 = ( _last.x() - rect.x() ) / double( rect.width() ); + m_s2 = 1; + } + else if( m_activeNode == node_rt ) + { + m_sp = KoPoint( rect.x(), rect.y() ); + m_s1 = ( _last.x() - rect.x() ) / double( rect.width() ); + m_s2 = ( _last.y() - rect.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_mt ) + { + m_sp = KoPoint( ( ( rect.right() + rect.left() ) / 2 ), rect.y() ); + m_s1 = 1; + m_s2 = ( _last.y() - rect.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_lt ) + { + m_sp = KoPoint( rect.right(), rect.y() ); + m_s1 = ( rect.right() - _last.x() ) / double( rect.width() ); + m_s2 = ( _last.y() - rect.y() ) / double( rect.height() ); + } + else if( m_activeNode == node_lm ) + { + m_sp = KoPoint( rect.right(), ( rect.bottom() + rect.top() ) / 2 ); + m_s1 = ( rect.right() - _last.x() ) / double( rect.width() ); + m_s2 = 1; + } + + if( shiftPressed() ) + m_s1 = m_s2 = kMax( m_s1, m_s2 ); + cmd = new VScaleCmd( 0L, m_sp, m_s1, m_s2 ); + } + + // Copy selected objects and transform: + m_objects.clear(); + VObject* copy; + + VObjectListIterator itr = view()->part()->document().selection()->objects(); + for( ; itr.current() ; ++itr ) + { + if( itr.current()->state() != VObject::deleted ) + { + copy = itr.current()->clone(); + copy->setState( VObject::edit ); + + cmd->visit( *copy ); + + m_objects.append( copy ); + } + } + + delete( cmd ); + } +} + +bool +VSelectTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VSelectTool::refreshUnit() +{ + updateStatusBar(); +} + +void +VSelectTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Select Tool" ), "14_select", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Select" ) ); + m_action->setExclusiveGroup( "select" ); + //m_ownAction = true; + } +} + +#include "vselecttool.moc" diff --git a/karbon/tools/vselecttool.h b/karbon/tools/vselecttool.h new file mode 100644 index 00000000..3ef50cab --- /dev/null +++ b/karbon/tools/vselecttool.h @@ -0,0 +1,110 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTTOOL_H__ +#define __VSELECTTOOL_H__ + +#include <kdialogbase.h> +#include <klocale.h> + +#include "vtool.h" + +class KarbonView; + +class VSelectOptionsWidget : public KDialogBase +{ +Q_OBJECT + +public: + VSelectOptionsWidget( KarbonPart* part ); + +public slots: + void modeChange( int mode ); + +private: + KarbonPart* m_part; +}; // VSelectOptionsWidget + +class VSelectTool : public VTool +{ +Q_OBJECT + +public: + VSelectTool( KarbonView *view ); + virtual ~VSelectTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Select Tool" ); } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual QString statusText(); + virtual uint priority() { return 0; } + virtual QString contextHelp(); + + virtual void refreshUnit(); + + virtual void activate(); + +protected: + virtual void draw(); + + virtual void setCursor() const; + + virtual void mouseButtonPress(); + virtual void rightMouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void rightMouseButtonRelease(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + virtual void mouseDragCtrlPressed(); + virtual void mouseDragCtrlReleased(); + virtual void mouseDragShiftPressed(); + virtual void mouseDragShiftReleased(); + virtual void arrowKeyReleased( Qt::Key ); + virtual bool keyReleased( Qt::Key ); + + virtual void cancel(); + +protected slots: + void updateStatusBar() const; + +private: + enum { normal, moving, scaling, rotating } m_state; + bool m_lock; + // controls if objects are added to or removed from the selection + bool m_add; + double m_s1; + double m_s2; + double m_distx; + double m_disty; + KoPoint m_sp; + KoPoint m_current; + + VHandleNode m_activeNode; + + void recalc(); + + // A list of temporary objects: + VObjectList m_objects; + // The options widget. + VSelectOptionsWidget *m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vshapetool.cc b/karbon/tools/vshapetool.cc new file mode 100644 index 00000000..5ec04084 --- /dev/null +++ b/karbon/tools/vshapetool.cc @@ -0,0 +1,274 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcursor.h> +#include <qevent.h> +#include <qlabel.h> + +#include "karbon_part.h" +#include "karbon_view.h" +#include "vcanvas.h" +#include "vcomposite.h" +#include "vglobal.h" +#include "vpainter.h" +#include "vpainterfactory.h" +#include "vshapecmd.h" +#include "vshapetool.h" +#include "vselection.h" +#include "vcursor.h" + +VShapeTool::VShapeTool( KarbonView *view, const char *name, bool polar ) + : VTool( view, name ) +{ + m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) ); + + m_isPolar = polar; + m_isSquare = false; + m_isCentered = false; +} + +VShapeTool::~VShapeTool() +{ + delete m_cursor; +} + +QString +VShapeTool::contextHelp() +{ + QString s = i18n( "<qt><b>Shape tool</b><br>" ); + s += i18n( "<i>Click and drag</i> to place your own shape.<br>" ); + s += i18n( "<i>Click</i> to place a shape using the tool properties values.</qt>" ); + return s; +} + +void +VShapeTool::activate() +{ + VTool::activate(); + view()->setCursor( *m_cursor ); + view()->part()->document().selection()->showHandle( true ); +} + +QString +VShapeTool::statusText() +{ + return uiname(); +} + +void +VShapeTool::draw() +{ + VPainter* painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + VPath* composite = shape(); + composite->setState( VPath::edit ); + composite->draw( painter, &composite->boundingBox() ); + delete( composite ); +} + +void +VShapeTool::mouseButtonPress() +{ + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::mouseButtonRelease() +{ + draw(); + + recalc(); + + if( showDialog() ) + { + VPath* composite = shape( true ); + + if( composite ) + { + VShapeCmd* cmd = new VShapeCmd( + &view()->part()->document(), + uiname(), composite, icon() ); + + view()->part()->addCommand( cmd, true ); + } + } + + m_isSquare = false; + m_isCentered = false; +} + +void +VShapeTool::mouseDrag() +{ + // Erase old object: + draw(); + + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::mouseDragRelease() +{ + //recalc(); + + VShapeCmd* cmd = new VShapeCmd( + &view()->part()->document(), + uiname(), shape(), icon() ); + + view()->part()->addCommand( cmd, true ); + + m_isSquare = false; + m_isCentered = false; +} + +void +VShapeTool::mouseDragShiftPressed() +{ + // Erase old object: + draw(); + + m_isSquare = true; + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::mouseDragCtrlPressed() +{ + // Erase old object: + draw(); + + m_isCentered = true; + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::mouseDragShiftReleased() +{ + // Erase old object: + draw(); + + m_isSquare = false; + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::mouseDragCtrlReleased() +{ + // Erase old object: + draw(); + + m_isCentered = false; + recalc(); + + // Draw new object: + draw(); +} + +void +VShapeTool::cancel() +{ + // Erase old object: + if ( isDragging() ) + { + draw(); + m_isSquare = false; + m_isCentered = false; + } +} + +void +VShapeTool::recalc() +{ + m_isSquare = shiftPressed(); + m_isCentered = ctrlPressed(); + + KoPoint _first = view()->canvasWidget()->snapToGrid( first() ); + KoPoint _last = view()->canvasWidget()->snapToGrid( last() ); + + // Calculate radius and angle: + if( m_isPolar ) + { + // Radius: + m_d1 = sqrt( + ( _last.x() - _first.x() ) * ( _last.x() - _first.x() ) + + ( _last.y() - _first.y() ) * ( _last.y() - _first.y() ) ); + + // Angle: + m_d2 = atan2( _last.y() - _first.y(), _last.x() - _first.x() ); + + // Define pi/2 as "0.0": + m_d2 -= VGlobal::pi_2; + + m_p = _first; + } + else + // Calculate width and height: + { + m_d1 = _last.x() - _first.x(); + m_d2 = _last.y() - _first.y(); + + const int m_sign1 = VGlobal::sign( m_d1 ); +// TODO: revert when we introduce y-mirroring: + const int m_sign2 = VGlobal::sign( -m_d2 ); + + // Make unsigned: + if( m_d1 < 0.0 ) + m_d1 = -m_d1; + + if( m_d2 < 0.0 ) + m_d2 = -m_d2; + + if ( m_isSquare ) + { + if ( m_d1 > m_d2 ) + m_d2 = m_d1; + else + m_d1 = m_d2; + } + + m_p.setX( + _first.x() - ( m_sign1 == -1 ? m_d1 : 0.0 ) ); +// TODO: revert when we introduce y-mirroring: + m_p.setY( + _first.y() + ( m_sign2 == -1 ? m_d2 : 0.0 ) ); + + if ( m_isCentered ) + { + m_p.setX( m_p.x() - m_sign1 * qRound( m_d1 * 0.5 ) ); + m_p.setY( m_p.y() + m_sign2 * qRound( m_d2 * 0.5 ) ); + } + } +} + diff --git a/karbon/tools/vshapetool.h b/karbon/tools/vshapetool.h new file mode 100644 index 00000000..48cfa4c7 --- /dev/null +++ b/karbon/tools/vshapetool.h @@ -0,0 +1,83 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSHAPETOOL_H__ +#define __VSHAPETOOL_H__ + +#include <qstring.h> + +#include <KoPoint.h> + +#include "vtool.h" + + +class VPath; +class VCursor; + +class VShapeTool : public VTool +{ +public: + VShapeTool( KarbonView *view, const char *name, bool polar = false ); + + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual QString statusText(); + virtual QString contextHelp(); + + virtual void activate(); + +protected: + virtual void draw(); + + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + virtual void mouseDragShiftPressed(); + virtual void mouseDragCtrlPressed(); + virtual void mouseDragShiftReleased(); + virtual void mouseDragCtrlReleased(); + + virtual void cancel(); + + // Make it "abstract": + virtual ~VShapeTool(); + + virtual VPath* shape( bool interactive = false ) const = 0; + + /** + * Output coordinates. + */ + KoPoint m_p; + double m_d1; + double m_d2; + +private: + void recalc(); + + /// Calculate width/height or radius/angle? + bool m_isPolar; + + /// States: + bool m_isSquare; + bool m_isCentered; + + QCursor* m_cursor; +}; + +#endif diff --git a/karbon/tools/vsheartool.cc b/karbon/tools/vsheartool.cc new file mode 100644 index 00000000..e38336b1 --- /dev/null +++ b/karbon/tools/vsheartool.cc @@ -0,0 +1,219 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <qcursor.h> +#include <qlabel.h> + +#include <klocale.h> +#include <KoRect.h> + +#include <karbon_part.h> +#include <karbon_view.h> +#include <render/vpainter.h> +#include <render/vpainterfactory.h> +#include <vselection.h> +#include "vsheartool.h" +#include <commands/vtransformcmd.h> + +VShearTool::VShearTool( KarbonView *view ) : VTool( view, "sheartool" ) +{ + setName( "tool_shear" ); + m_objects.setAutoDelete( true ); + registerTool( this ); +} + +VShearTool::~VShearTool() +{ +} + +void +VShearTool::activate() +{ + view()->setCursor( QCursor( Qt::arrowCursor ) ); + view()->part()->document().selection()->showHandle( true ); + view()->part()->document().selection()->setState( VObject::selected ); + VTool::activate(); +} + +QString +VShearTool::statusText() +{ + return i18n( "Shear" ); +} + +void +VShearTool::draw() +{ + VPainter* painter = view()->painterFactory()->editpainter(); + painter->setRasterOp( Qt::NotROP ); + + VObjectListIterator itr = m_objects; + for( ; itr.current(); ++itr ) + itr.current()->draw( painter, &itr.current()->boundingBox() ); +} + +void +VShearTool::setCursor() const +{ + if( isDragging() ) return; + switch( view()->part()->document().selection()->handleNode( last() ) ) + { + case node_lt: + case node_rb: + view()->setCursor( QCursor( Qt::SizeFDiagCursor ) ); + break; + case node_rt: + case node_lb: + view()->setCursor( QCursor( Qt::SizeBDiagCursor ) ); + break; + case node_lm: + case node_rm: + view()->setCursor( QCursor( Qt::SizeHorCursor ) ); + break; + case node_mt: + case node_mb: + view()->setCursor( QCursor( Qt::SizeVerCursor ) ); + break; + default: + view()->setCursor( QCursor( Qt::arrowCursor ) ); + } +} + +void +VShearTool::mouseButtonPress() +{ + view()->painterFactory()->painter()->end(); + m_activeNode = view()->part()->document().selection()->handleNode( first() ); + recalc(); + + // Draw new object: + draw(); +} + +void +VShearTool::mouseDrag( ) +{ + // Erase old object: + draw(); + + recalc(); + + // Draw new object: + draw(); +} + + +void +VShearTool::mouseDragRelease() +{ + view()->part()->addCommand( + new VShearCmd( &view()->part()->document(), m_center, m_s1, m_s2, altPressed() ), + true ); +} + +void +VShearTool::cancel() +{ + // Erase old object: + if ( isDragging() ) + { + draw(); + view()->repaintAll( view()->part()->document().selection()->boundingBox() ); + } +} + +void +VShearTool::recalc() +{ + KoRect rect = view()->part()->document().selection()->boundingBox(); + + if( m_activeNode == node_lt ) + { + } + else if( m_activeNode == node_mt ) + { + m_s1 = 0; + m_s2 = ( last().y() - first().y() ) / double( ( rect.height() / 2 ) ); + } + else if( m_activeNode == node_rt ) + { + } + else if( m_activeNode == node_rm) + { + m_s1 = ( last().x() - first().x() ) / double( ( rect.width() / 2 ) ); + m_s2 = 0; + } + else if( m_activeNode == node_rb ) + { + } + else if( m_activeNode == node_mb ) + { + m_s1 = 0; + m_s2 = ( last().y() - first().y() ) / double( ( rect.height() / 2 ) ); + } + else if( m_activeNode == node_lb ) + { + } + else if( m_activeNode == node_lm ) + { + m_s1 = ( last().x() - first().x() ) / double( ( rect.width() / 2 ) ); + m_s2 = 0; + } + + // Get center: + m_center = view()->part()->document().selection()->boundingBox().center(); + + VShearCmd cmd( 0L, m_center, m_s1, m_s2 ); + + // Copy selected objects and transform: + m_objects.clear(); + VObject* copy; + + VObjectListIterator itr = view()->part()->document().selection()->objects(); + for ( ; itr.current() ; ++itr ) + { + if( itr.current()->state() != VObject::deleted ) + { + copy = itr.current()->clone(); + + cmd.visit( *copy ); + + copy->setState( VObject::edit ); + + m_objects.append( copy ); + } + } +} + +void +VShearTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Shear Tool" ), "14_shear", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Shear" ) ); + m_action->setExclusiveGroup( "manipulation" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vsheartool.h b/karbon/tools/vsheartool.h new file mode 100644 index 00000000..eb3be26c --- /dev/null +++ b/karbon/tools/vsheartool.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSHEARTOOL_H__ +#define __VSHEARTOOL_H__ + +#include "vtool.h" + +class VShearTool : public VTool +{ +public: + VShearTool( KarbonView *view ); + virtual ~VShearTool(); + + virtual void activate(); + + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Shear Tool" ); } + virtual enumToolType toolType() { return TOOL_MANIPULATION; } + virtual uint priority() { return 1; } + virtual QString statusText(); + +protected: + virtual void draw(); + + virtual void setCursor() const; + virtual void mouseButtonPress(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + + virtual void cancel(); + +private: + void recalc(); + + KoPoint m_center; + double m_s1, m_s2; + + VHandleNode m_activeNode; + + // A list of temporary objects: + VObjectList m_objects; +}; + +#endif + diff --git a/karbon/tools/vsinustool.cc b/karbon/tools/vsinustool.cc new file mode 100644 index 00000000..056b88c9 --- /dev/null +++ b/karbon/tools/vsinustool.cc @@ -0,0 +1,162 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> + +#include <klocale.h> +#include <knuminput.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vsinus.h> +#include "vsinustool.h" +#include "KoUnitWidgets.h" + + +VSinusTool::VSinusOptionsWidget::VSinusOptionsWidget( KarbonPart *part, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Sinus" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + // add width/height-input: + m_widthLabel = new QLabel( i18n( "object width", "Width:" ), group ); + m_width = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + m_heightLabel = new QLabel( i18n( "Height:" ), group ); + m_height = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 100.0, KoUnit::U_MM ); + + refreshUnit(); + + new QLabel( i18n( "Periods:" ), group ); + m_periods = new KIntSpinBox( group ); + m_periods->setMinValue( 1 ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +double +VSinusTool::VSinusOptionsWidget::width() const +{ + return m_width->value(); +} + +double +VSinusTool::VSinusOptionsWidget::height() const +{ + return m_height->value(); +} + +uint +VSinusTool::VSinusOptionsWidget::periods() const +{ + return m_periods->value(); +} + +void +VSinusTool::VSinusOptionsWidget::setWidth( double value ) +{ + m_width->changeValue( value ); +} + +void +VSinusTool::VSinusOptionsWidget::setHeight( double value ) +{ + m_height->changeValue( value ); +} + +void +VSinusTool::VSinusOptionsWidget::setPeriods( uint value ) +{ + m_periods->setValue( value ); +} + +void +VSinusTool::VSinusOptionsWidget::refreshUnit () +{ + m_width->setUnit( m_part->unit() ); + m_height->setUnit( m_part->unit() ); +} + +VSinusTool::VSinusTool( KarbonView *view ) + : VShapeTool( view, "tool_sinus" ) +{ + // create config widget: + m_optionsWidget = new VSinusOptionsWidget( view->part() ); + m_optionsWidget->setPeriods( 1 ); + registerTool( this ); +} + +VSinusTool::~VSinusTool() +{ + delete( m_optionsWidget ); +} + +void +VSinusTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +VPath* +VSinusTool::shape( bool interactive ) const +{ + if( interactive ) + return + new VSinus( + 0L, + m_p, + m_optionsWidget->width(), + m_optionsWidget->height(), + m_optionsWidget->periods() ); + else + return + new VSinus( + 0L, + m_p, + m_d1, + m_d2, + m_optionsWidget->periods() ); +} + +bool +VSinusTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VSinusTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Sinus Tool" ), "14_sinus", Qt::SHIFT+Qt::Key_S, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Sinus" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vsinustool.h b/karbon/tools/vsinustool.h new file mode 100644 index 00000000..6fcfd45c --- /dev/null +++ b/karbon/tools/vsinustool.h @@ -0,0 +1,72 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSINUSTOOL_H__ +#define __VSINUSTOOL_H__ + +#include <kdialogbase.h> +#include "vshapetool.h" + +class KoUnitDoubleSpinBox; +class KIntSpinBox; +class KarbonView; +class QLabel; + +class VSinusTool : public VShapeTool +{ +public: + VSinusTool( KarbonView *view ); + virtual ~VSinusTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Sinus Tool" ); } + + virtual VPath *shape( bool interactive = false ) const; + + void refreshUnit(); + +private: + class VSinusOptionsWidget : public KDialogBase + { + public: + VSinusOptionsWidget( KarbonPart *part, QWidget *parent = 0L, const char *name = 0L ); + + double width() const; + double height() const; + uint periods() const; + void setWidth( double value ); + void setHeight( double value ); + void setPeriods( uint value ); + void refreshUnit(); + + private: + KoUnitDoubleSpinBox *m_width; + KoUnitDoubleSpinBox *m_height; + KIntSpinBox *m_periods; + KarbonPart *m_part; + QLabel *m_heightLabel; + QLabel *m_widthLabel; + }; + + VSinusOptionsWidget *m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vspiraltool.cc b/karbon/tools/vspiraltool.cc new file mode 100644 index 00000000..f4c3fff6 --- /dev/null +++ b/karbon/tools/vspiraltool.cc @@ -0,0 +1,213 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qgroupbox.h> + +#include <klocale.h> +#include <kcombobox.h> +#include <knuminput.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vspiral.h> +#include "vspiraltool.h" +#include "KoUnitWidgets.h" + + +VSpiralTool::VSpiralOptionsWidget::VSpiralOptionsWidget( KarbonPart *part, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Spiral" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + + new QLabel( i18n( "Type:" ), group ); + m_type = new KComboBox( false, group ); + m_type->insertItem( i18n( "Round" ), 0 ); + m_type->insertItem( i18n( "Rectangular" ), 1 ); + + new QLabel( i18n( "Radius:" ), group ); + m_radius = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 50.0, KoUnit::U_MM ); + refreshUnit(); + new QLabel( i18n( "Segments:" ), group ); + m_segments = new KIntSpinBox( group ); + m_segments->setMinValue( 1 ); + new QLabel( i18n( "Fade:" ), group ); + m_fade = new KDoubleNumInput( group ); + m_fade->setRange( 0.0, 1.0, 0.05 ); + + new QLabel( i18n( "Orientation:" ), group ); + m_clockwise = new KComboBox( false, group ); + m_clockwise->insertItem( i18n( "Clockwise" ), 0 ); + m_clockwise->insertItem( i18n( "Counter Clockwise" ), 1 ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + //setFixedSize( baseSize() ); +} + +double +VSpiralTool::VSpiralOptionsWidget::radius() const +{ + return m_radius->value(); +} + +uint +VSpiralTool::VSpiralOptionsWidget::segments() const +{ + return m_segments->value(); +} + +double +VSpiralTool::VSpiralOptionsWidget::fade() const +{ + return m_fade->value(); +} + +bool +VSpiralTool::VSpiralOptionsWidget::clockwise() const +{ + return m_clockwise->currentItem() == 0; +} + +uint +VSpiralTool::VSpiralOptionsWidget::type() const +{ + return m_type->currentItem(); +} + +void +VSpiralTool::VSpiralOptionsWidget::setRadius( double value ) +{ + m_radius->changeValue( value ); +} + +void +VSpiralTool::VSpiralOptionsWidget::setSegments( uint value ) +{ + m_segments->setValue( value ); +} + +void +VSpiralTool::VSpiralOptionsWidget::setFade( double value ) +{ + m_fade->setValue( value ); +} + +void +VSpiralTool::VSpiralOptionsWidget::setClockwise( bool value ) +{ + m_clockwise->setCurrentItem( value ? 0 : 1 ); +} + +void +VSpiralTool::VSpiralOptionsWidget::refreshUnit() +{ + m_radius->setUnit( m_part->unit() ); +} + +VSpiralTool::VSpiralTool( KarbonView *view ) + : VShapeTool( view, "tool_spiral", true ) +{ + // create config dialog: + m_optionsWidget = new VSpiralOptionsWidget( view->part() ); + m_optionsWidget->setSegments( 8 ); + m_optionsWidget->setFade( 0.8 ); + m_optionsWidget->setClockwise( true ); + registerTool( this ); +} + +void +VSpiralTool::arrowKeyReleased( Qt::Key key ) +{ + int change = 0; + if( key == Qt::Key_Up ) + change = 1; + else if( key == Qt::Key_Down ) + change = -1; + + if( change != 0 ) + { + draw(); + + m_optionsWidget->setSegments( m_optionsWidget->segments() + change ); + + draw(); + } +} + +VSpiralTool::~VSpiralTool() +{ + delete( m_optionsWidget ); +} + +void +VSpiralTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +VPath* +VSpiralTool::shape( bool interactive ) const +{ + if( interactive ) + { + return + new VSpiral( + 0L, + m_p, + m_optionsWidget->radius(), + m_optionsWidget->segments(), + m_optionsWidget->fade(), + m_optionsWidget->clockwise(), + m_d2, (VSpiral::VSpiralType)m_optionsWidget->type() ); + } + else + return + new VSpiral( + 0L, + m_p, + m_d1, + m_optionsWidget->segments(), + m_optionsWidget->fade(), + m_optionsWidget->clockwise(), + m_d2, (VSpiral::VSpiralType)m_optionsWidget->type() ); +} + +bool +VSpiralTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VSpiralTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Spiral Tool" ), "14_spiral", Qt::SHIFT+Qt::Key_H, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Spiral" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + diff --git a/karbon/tools/vspiraltool.h b/karbon/tools/vspiraltool.h new file mode 100644 index 00000000..2976deda --- /dev/null +++ b/karbon/tools/vspiraltool.h @@ -0,0 +1,81 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSPIRALTOOL_H__ +#define __VSPIRALTOOL_H__ + +#include <kdialogbase.h> +#include <klocale.h> + +#include "vshapetool.h" + +class KComboBox; +class KoUnitDoubleSpinBox; +class KDoubleNumInput; +class KIntSpinBox; +class KarbonView; + +class VSpiralTool : public VShapeTool +{ +public: + VSpiralTool( KarbonView *view ); + virtual ~VSpiralTool(); + + virtual void setup(KActionCollection *collection); + virtual bool showDialog() const; + virtual QString uiname() { return i18n( "Spiral Tool" ); } + + virtual VPath* shape( bool interactive = false ) const; + + void refreshUnit(); + + virtual void arrowKeyReleased( Qt::Key ); + +private: + class VSpiralOptionsWidget : public KDialogBase + { + public: + VSpiralOptionsWidget( KarbonPart *part, QWidget *parent = 0L, const char* name = 0L ); + + double radius() const; + uint segments() const; + double fade() const; + uint type() const; + bool clockwise() const; + void setRadius( double value ); + void setSegments( uint value ); + void setFade( double value ); + void setClockwise( bool value ); + + void refreshUnit(); + + private: + KoUnitDoubleSpinBox *m_radius; + KIntSpinBox *m_segments; + KDoubleNumInput *m_fade; + KComboBox *m_type; + KComboBox *m_clockwise; + KarbonPart *m_part; + }; + + VSpiralOptionsWidget *m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vstartool.cc b/karbon/tools/vstartool.cc new file mode 100644 index 00000000..612a0bce --- /dev/null +++ b/karbon/tools/vstartool.cc @@ -0,0 +1,249 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qgroupbox.h> + +#include <klocale.h> +#include <knuminput.h> +#include <kcombobox.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <shapes/vstar.h> +#include "vstartool.h" +#include "KoUnitWidgets.h" + + +VStarOptionsWidget::VStarOptionsWidget( KarbonPart *part, QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, i18n( "Insert Star" ), Ok | Cancel ), m_part( part ) +{ + QGroupBox *group = new QGroupBox( 2, Qt::Horizontal, i18n( "Properties" ), this ); + new QLabel( i18n( "Type:" ), group ); + m_type = new KComboBox( false, group ); + m_type->insertItem( i18n( "Star Outline" ), VStar::star_outline ); + m_type->insertItem( i18n( "Spoke" ), VStar::spoke ); + m_type->insertItem( i18n( "Wheel" ), VStar::wheel ); + m_type->insertItem( i18n( "Polygon" ), VStar::polygon ); + m_type->insertItem( i18n( "Framed Star" ), VStar::framed_star); + m_type->insertItem( i18n( "Star" ), VStar::star ); + m_type->insertItem( i18n( "Gear" ), VStar::gear ); + connect( m_type, SIGNAL( activated( int ) ), this, SLOT( typeChanged( int ) ) ); + + // add width/height-input: + m_outerRLabel = new QLabel( i18n( "Outer radius:" ), group ); + m_outerR = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 50.0, KoUnit::U_MM ); + connect( m_outerR, SIGNAL( valueChanged( double ) ), this, SLOT( setOuterRadius( double ) ) ); + + m_innerRLabel = new QLabel( i18n( "Inner radius:" ), group ); + m_innerR = new KoUnitDoubleSpinBox( group, 0.0, 1000.0, 0.5, 25.0, KoUnit::U_MM ); + + refreshUnit(); + + new QLabel( i18n( "Edges:" ), group ); + m_edges = new KIntSpinBox( group ); + m_edges->setMinValue( 3 ); + connect( m_edges, SIGNAL( valueChanged( int ) ), this, SLOT( setEdges( int ) ) ); + + new QLabel( i18n( "Inner angle:" ), group ); + m_innerAngle = new KIntSpinBox( group ); + m_innerAngle->setMinValue( 0 ); + m_innerAngle->setMaxValue( 360 ); + + new QLabel( i18n( "Roundness:" ), group ); + m_roundness = new KDoubleNumInput( group ); + m_roundness->setRange( 0.0, 1.0, 0.05 ); + + typeChanged( VStar::star_outline ); + + group->setInsideMargin( 4 ); + group->setInsideSpacing( 2 ); + + setMainWidget( group ); + setFixedSize( baseSize() ); +} + +void +VStarOptionsWidget::refreshUnit() +{ + m_outerR->setUnit( m_part->unit() ); + m_innerR->setUnit( m_part->unit() ); +} + +void +VStarOptionsWidget::setEdges( int v ) +{ + m_edges->setValue( v ); + + // set optimal inner radius + if( type() == VStar::star ) + m_innerR->setValue( VStar::getOptimalInnerRadius( edges(), outerRadius(), innerAngle() ) ); +} + +void +VStarOptionsWidget::setInnerRadius( double v ) +{ + m_innerR->changeValue( v ); +} + +void +VStarOptionsWidget::setOuterRadius( double v ) +{ + m_outerR->setValue( v ); + + // set optimal inner radius + if( type() == VStar::star ) + m_innerR->setValue( VStar::getOptimalInnerRadius( edges(), outerRadius(), innerAngle() ) ); +} + +double +VStarOptionsWidget::roundness() const +{ + return m_roundness->value(); +} + +int +VStarOptionsWidget::edges() const +{ + return m_edges->value(); +} + +double +VStarOptionsWidget::innerRadius() const +{ + return m_innerR->value(); +} + +double +VStarOptionsWidget::outerRadius() const +{ + return m_outerR->value(); +} + +uint +VStarOptionsWidget::type() const +{ + return m_type->currentItem(); +} + +uint +VStarOptionsWidget::innerAngle() const +{ + return m_innerAngle->value(); +} + +void +VStarOptionsWidget::typeChanged( int type ) +{ + m_innerR->setEnabled( type == VStar::star || type == VStar::star_outline || type == VStar::framed_star || type == VStar::gear ); + m_innerAngle->setEnabled( type == VStar::star || type == VStar::star_outline || type == VStar::framed_star || type == VStar::gear ); + + // set optimal inner radius + if( type == VStar::star ) + m_innerR->changeValue( VStar::getOptimalInnerRadius( edges(), outerRadius(), innerAngle() ) ); +} + +VStarTool::VStarTool( KarbonView *view ) + : VShapeTool( view, "tool_star", true ) +{ + // create config dialog: + m_optionsWidget = new VStarOptionsWidget( view->part() ); + m_optionsWidget->setEdges( 5 ); + registerTool( this ); +} + +void VStarTool::refreshUnit() +{ + m_optionsWidget->refreshUnit(); +} + +VStarTool::~VStarTool() +{ + delete( m_optionsWidget ); +} + +void +VStarTool::arrowKeyReleased( Qt::Key key ) +{ + int change = 0; + if( key == Qt::Key_Up ) + change = 1; + else if( key == Qt::Key_Down ) + change = -1; + + if( change != 0 ) + { + draw(); + + m_optionsWidget->setEdges( m_optionsWidget->edges() + change ); + + draw(); + } +} + +VPath* +VStarTool::shape( bool interactive ) const +{ + if( interactive ) + { + return + new VStar( + 0L, + m_p, + m_optionsWidget->outerRadius(), + m_optionsWidget->innerRadius(), + m_optionsWidget->edges(), 0.0, m_optionsWidget->innerAngle(), + m_optionsWidget->roundness(), (VStar::VStarType)m_optionsWidget->type() ); + } + else + return + new VStar( + 0L, + m_p, + m_d1, + m_optionsWidget->innerRadius() * m_d1 / + m_optionsWidget->outerRadius(), + m_optionsWidget->edges(), + m_d2, m_optionsWidget->innerAngle(), + m_optionsWidget->roundness(), (VStar::VStarType)m_optionsWidget->type() ); +} + +bool +VStarTool::showDialog() const +{ + return m_optionsWidget->exec() == QDialog::Accepted; +} + +void +VStarTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + KShortcut shortcut( Qt::Key_Plus ); + shortcut.append(KShortcut( Qt::Key_F9 ) ); + m_action = new KRadioAction( i18n( "Star Tool" ), "14_star", shortcut, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Draw a star" ) ); + m_action->setExclusiveGroup( "shapes" ); + //m_ownAction = true; + } +} + +#include "vstartool.moc" diff --git a/karbon/tools/vstartool.h b/karbon/tools/vstartool.h new file mode 100644 index 00000000..f9ec716b --- /dev/null +++ b/karbon/tools/vstartool.h @@ -0,0 +1,87 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTARTOOL_H__ +#define __VSTARTOOL_H__ + +#include <klocale.h> +#include <kdialogbase.h> + +#include "vshapetool.h" + + +class KoUnitDoubleSpinBox; +class KIntSpinBox; +class KComboBox; +class KarbonView; + +class VStarOptionsWidget : public KDialogBase +{ +Q_OBJECT +public: + VStarOptionsWidget( KarbonPart *part, QWidget* parent = 0L, const char* name = 0L ); + + void refreshUnit(); + + int edges() const; + double innerRadius() const; + double outerRadius() const; + double roundness() const; + uint type() const; + uint innerAngle() const; + void setInnerRadius( double ); + +public slots: + void typeChanged( int ); + void setEdges( int ); + void setOuterRadius( double ); + +private: + KoUnitDoubleSpinBox *m_innerR; + KoUnitDoubleSpinBox *m_outerR; + KDoubleNumInput *m_roundness; + KIntSpinBox *m_edges; + KIntSpinBox *m_innerAngle; + KComboBox *m_type; + KarbonPart *m_part; + QLabel *m_innerRLabel; + QLabel *m_outerRLabel; +}; + +class VStarTool : public VShapeTool +{ +public: + VStarTool( KarbonView *view ); + virtual ~VStarTool(); + + virtual bool showDialog() const; + virtual void setup(KActionCollection *collection); + virtual QString uiname() { return i18n( "Star Tool" ); } + virtual VPath* shape( bool interactive = false ) const; + + void refreshUnit(); + + virtual void arrowKeyReleased( Qt::Key ); + +private: + VStarOptionsWidget* m_optionsWidget; +}; + +#endif + diff --git a/karbon/tools/vtexttool.cc b/karbon/tools/vtexttool.cc new file mode 100644 index 00000000..1d59ebda --- /dev/null +++ b/karbon/tools/vtexttool.cc @@ -0,0 +1,1159 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qcursor.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qtabwidget.h> + +#include <kdebug.h> +#include <kfontcombo.h> +#include <kfontdialog.h> +#include <kiconloader.h> +#include <knuminput.h> +#include <kglobalsettings.h> + +#include <karbon_view.h> +#include <karbon_part.h> +#include <core/vdocument.h> +#include <core/vglobal.h> +#include <core/vselection.h> +#include <core/vfill.h> +#include <core/vgroup.h> +#include <core/vstroke.h> +#include <core/vcursor.h> +#include <render/vpainterfactory.h> +#include <render/vkopainter.h> +#include "vtexttool.h" + + +static void +traceShape( VKoPainter* p, int x, int y, int w, int h ) +{ + p->newPath(); + p->moveTo( KoPoint( x + w , y + h ) ); + p->lineTo( KoPoint( x + w / 3, y + h ) ); + p->lineTo( KoPoint( x + w / 3, y + h / 3 ) ); + p->lineTo( KoPoint( x + w , y + h / 3 ) ); + p->lineTo( KoPoint( x + w , y + h ) ); + + p->moveTo( KoPoint( x , y ) ); + p->lineTo( KoPoint( x + ( w / 3 ) * 2, y ) ); + p->lineTo( KoPoint( x + ( w / 3 ) * 2, y + ( h / 3 ) * 2 ) ); + p->lineTo( KoPoint( x , y + ( h / 3 ) * 2 ) ); + p->lineTo( KoPoint( x , y ) ); +} + +ShadowPreview::ShadowPreview( ShadowWidget* parent ) + : QWidget( parent ), m_parent( parent ) +{ + setBackgroundMode( Qt::NoBackground ); + setMinimumSize( 60, 60 ); + + connect( this, SIGNAL( changed( int, int, bool ) ), m_parent, SLOT( setShadowValues( int, int, bool ) ) ); +} + +ShadowPreview::~ShadowPreview() +{ +} + +void +ShadowPreview::mouseReleaseEvent( QMouseEvent* e ) +{ + int dx = e->x() - width() / 2; + int dy = e->y() - height() / 2; + + float fd = sqrt( double( dx * dx + dy * dy ) ); + int a; + + if( fd == 0 ) + a = 0; + else if( dy == 0 && dx < 0 ) + a = 180; + else + { + float r = acos( dx / fd ); + a = int( ( dy <= 0 ? r : VGlobal::twopi - r ) / VGlobal::twopi * 360. ); + } + + emit changed( a, ( int ) fd, m_parent->isTranslucent() ); +} + +void +ShadowPreview::paintEvent( QPaintEvent* ) +{ + int w = width() - 4; + int h = height() - 4; + int d = m_parent->shadowDistance(); + int a = 360 - m_parent->shadowAngle(); + + QPixmap pm( w, h ); + VKoPainter p( &pm, w, h ); + VColor color( VColor::rgb ); + + VFill fill; + KIconLoader il; + fill.pattern() = VPattern( il.iconPath( "karbon.png", KIcon::Small ) ); + fill.setType( VFill::patt ); + + p.newPath(); + p.moveTo( KoPoint( 0, 0 ) ); + p.lineTo( KoPoint( 0, h ) ); + p.lineTo( KoPoint( w, h ) ); + p.lineTo( KoPoint( w, 0 ) ); + p.lineTo( KoPoint( 0, 0 ) ); + p.setBrush( fill ); + p.fillPath(); + + color.set( 1., 1., 1. ); + color.setOpacity( .5 ); + p.setBrush( VFill( color ) ); + p.fillPath(); + + if( m_parent->isTranslucent() ) + { + color.set( 0., 0., 0. ); + color.setOpacity( .3 ); + } + else + { + color.set( .3, .3, .3 ); + color.setOpacity( 1. ); + } + + p.setPen( VStroke( color ) ); + p.setBrush( VFill( color ) ); + + traceShape( + &p, + int( w / 4 + d * cos( a / 360. * VGlobal::twopi ) ), + int( h / 4 + d * sin( a / 360. * VGlobal::twopi ) ), int( w / 2 ), int( h / 2 ) ); + + p.strokePath(); + p.fillPath(); + + color.set( 0., 0., 1. ); + color.setOpacity( 1. ); + p.setBrush( VFill( color ) ); + color.set( 0., 0., .5 ); + p.setPen( VStroke( color ) ); + traceShape( &p, w / 4, h / 4, w / 2, h / 2 ); + p.strokePath(); + p.fillPath(); + + if( !m_parent->useShadow() ) + { + p.newPath(); + p.moveTo( KoPoint( 0, 0 ) ); + p.lineTo( KoPoint( 0, h ) ); + p.lineTo( KoPoint( w, h ) ); + p.lineTo( KoPoint( w, 0 ) ); + p.lineTo( KoPoint( 0, 0 ) ); + VColor c( colorGroup().background() ); + c.setOpacity( .8 ); + p.setBrush( VFill( c ) ); + p.fillPath(); + } + + p.end(); + + QPainter painter( this ); + painter.drawPixmap( 2, 2, pm ); + painter.setPen( colorGroup().light() ); + painter.moveTo( 1, height() - 1 ); + painter.lineTo( 1, 1 ); + painter.lineTo( width() - 1, 1 ); + painter.lineTo( width() - 1, height() - 1 ); + painter.lineTo( 1, height() - 1 ); + painter.setPen( colorGroup().dark() ); + painter.moveTo( 0, height() - 1 ); + painter.lineTo( 0, 0 ); + painter.lineTo( width() - 1, 0 ); + painter.moveTo( width() - 2, 2 ); + painter.lineTo( width() - 2, height() - 2 ); + painter.lineTo( 2, height() - 2 ); + painter.setPen( Qt::black ); + painter.drawLine( width() / 2 - 2, height() / 2, width() / 2 + 2, height() / 2 ); + painter.drawLine( width() / 2, height() / 2 - 2, width() / 2, height() / 2 + 2 ); +} + +ShadowWidget::ShadowWidget( QWidget* parent, const char* name, int angle, int distance, bool translucent ) + : QGroupBox( parent, name ) +{ + setTitle( i18n( "Shadow" ) ); + setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + + QGridLayout* layout = new QGridLayout( this ); + layout->addRowSpacing( 0, 12 ); + layout->setMargin( 3 ); + layout->setSpacing( 2 ); + layout->setColStretch( 0, 1 ); + layout->setColStretch( 1, 0 ); + layout->setColStretch( 2, 2 ); + layout->addMultiCellWidget( m_preview = new ShadowPreview( this ), 1, 3, 0, 0 ); + layout->addWidget( new QLabel( i18n( "Angle:" ), this ), 1, 1 ); + layout->addWidget( m_angle = new KIntNumInput( this ), 1, 2 ); + layout->addWidget( new QLabel( i18n( "Distance:" ), this ), 2, 1 ); + layout->addWidget( m_distance = new KIntNumInput( this ), 2, 2 ); + layout->addWidget( m_useShadow = new QCheckBox( i18n( "Shadow" ), this ), 3, 1 ); + layout->addWidget( m_translucent = new QCheckBox( i18n( "Draw translucent shadow" ), this ), 3, 2 ); + m_distance->setRange( 1, 37, 1, true ); + m_angle->setRange( 0, 360, 10, true ); + m_angle->setValue( angle ); + m_distance->setValue( distance ); + m_translucent->setChecked( translucent ); + + connect( m_angle, SIGNAL( valueChanged( int ) ), this, SLOT( updatePreview( int ) ) ); + connect( m_distance, SIGNAL( valueChanged( int ) ), this, SLOT( updatePreview( int ) ) ); + connect( m_useShadow, SIGNAL( clicked() ), this, SLOT( updatePreview() ) ); + connect( m_translucent, SIGNAL( clicked() ), this, SLOT( updatePreview() ) ); + + updatePreview(); +} + +ShadowWidget::~ShadowWidget() +{ +} + +void +ShadowWidget::setUseShadow( bool use ) +{ + m_useShadow->setChecked( use ); + updatePreview(); +} + +bool ShadowWidget::useShadow() +{ + return m_useShadow->isChecked(); +} + +void +ShadowWidget::setShadowAngle( int angle ) +{ + m_angle->setValue( angle ); + m_preview->repaint(); +} + +int +ShadowWidget::shadowAngle() +{ + return m_angle->value(); +} + +void +ShadowWidget::setShadowDistance( int distance ) +{ + m_distance->setValue( distance ); + m_preview->repaint(); +} + +int +ShadowWidget::shadowDistance() +{ + return m_distance->value(); +} + +void +ShadowWidget::setTranslucent( bool translucent ) +{ + m_translucent->setChecked( translucent ); + m_preview->repaint(); +} + +bool ShadowWidget::isTranslucent() +{ + return m_translucent->isChecked(); +} + +void +ShadowWidget::setShadowValues( int angle, int distance, bool translucent ) +{ + m_angle->setValue( angle ); + m_distance->setValue( distance ); + m_translucent->setChecked( translucent ); + updatePreview(); +} + +void +ShadowWidget::updatePreview( int ) +{ + m_preview->repaint(); +} + +void +ShadowWidget::updatePreview() +{ + m_preview->repaint(); + bool ok = m_useShadow->isChecked(); + m_angle->setEnabled( ok ); + m_distance->setEnabled( ok ); + m_translucent->setEnabled( ok ); +} + +VTextOptionsWidget::VTextOptionsWidget( VTextTool* tool, QWidget *parent ) + : KDialogBase( parent, "", true, i18n( "Text" ), Ok | Cancel ), m_tool( tool ) +{ + //setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + //setFrameStyle( Box | Sunken ); + QWidget *base = new QWidget( this ); + QVBoxLayout* mainLayout = new QVBoxLayout( base ); + mainLayout->setMargin( 3 ); + + mainLayout->add( m_tabWidget = new QTabWidget( base ) ); + + m_tabWidget->setFont( QFont( KGlobalSettings::generalFont().family() , 8 ) ); + + QWidget* textWidget = new QWidget( m_tabWidget ); + + QGridLayout* textLayout = new QGridLayout( textWidget ); + + QStringList list; + KFontChooser::getFontList( list, KFontChooser::SmoothScalableFonts ); + + textLayout->setMargin( 3 ); + textLayout->setSpacing( 2 ); + textLayout->addMultiCellWidget( m_fontCombo = new KFontCombo( list, textWidget ), 0, 0, 0, 2 ); + textLayout->addWidget( m_fontSize = new KIntNumInput( textWidget ), 1, 0 ); + textLayout->addWidget( m_boldCheck = new QCheckBox( i18n( "Bold" ), textWidget ), 1, 1 ); + textLayout->addWidget( m_italicCheck = new QCheckBox( i18n( "Italic" ), textWidget ), 1, 2 ); + textLayout->addMultiCellWidget( m_textEditor = new QLineEdit( textWidget ), 2, 2, 0, 2 ); + + m_tabWidget->addTab( textWidget, i18n( "Text" ) ); + + QWidget* posWidget = new QWidget( m_tabWidget ); + + QGridLayout* posLayout = new QGridLayout( posWidget ); + textLayout->setMargin( 3 ); + posLayout->setSpacing( 2 ); + posLayout->addWidget( new QLabel( i18n( "Alignment:" ), posWidget ), 0, 0 ); + posLayout->addWidget( m_textAlignment = new QComboBox( posWidget ), 0, 1 ); + posLayout->addWidget( new QLabel( i18n( "Position:" ), posWidget ), 1, 0 ); + posLayout->addWidget( m_textPosition = new QComboBox( posWidget ), 1, 1 ); + posLayout->addWidget( new QLabel( i18n( "Offset:" ), posWidget ), 2, 0 ); + posLayout->addWidget( m_textOffset = new KDoubleNumInput( posWidget ), 2, 1 ); + posLayout->setColStretch( 0, 0 ); + posLayout->setColStretch( 1, 1 ); + + m_tabWidget->addTab( posWidget, i18n( "Position" ) ); + + QWidget* fxWidget = new QWidget( m_tabWidget ); + + QVBoxLayout* fxLayout = new QVBoxLayout( fxWidget ); + + fxLayout->setMargin( 3 ); + fxLayout->setSpacing( 2 ); + fxLayout->add( m_shadow = new ShadowWidget( fxWidget, 0L, 315, 4, true ) ); + + QHBoxLayout* fxLayout2 = new QHBoxLayout( fxLayout ); + + fxLayout2->setSpacing( 2 ); + fxLayout2->addWidget( m_editBasePath = new QPushButton( i18n( "Edit Base Path" ), fxWidget ) ); + fxLayout2->addWidget( m_convertToShapes = new QPushButton( i18n( "Convert to Shapes" ), fxWidget ) ); + + m_tabWidget->addTab( fxWidget, i18n( "Effects" ) ); + + m_fontCombo->setCurrentText( KGlobalSettings::generalFont().family() ); + + m_fontSize->setValue( 12 ); + m_fontSize->setSuffix( " pt" ); + + m_textEditor->setMinimumHeight( 100 ); + m_textEditor->setText( i18n( "New text") ); + m_textEditor->selectAll(); + + m_convertToShapes->setEnabled( true ); + + m_textAlignment->insertItem( i18n( "Horizontal alignment", "Left") ); + m_textAlignment->insertItem( i18n( "Horizontal alignment", "Center") ); + m_textAlignment->insertItem( i18n( "Horizontal alignment", "Right") ); + + m_textPosition->insertItem( i18n( "Vertical alignment", "Above") ); + m_textPosition->insertItem( i18n( "Vertical alignment", "On") ); + m_textPosition->insertItem( i18n( "Vertical alignment", "Under") ); + + m_textOffset->setRange( 0.0, 100.0, 1.0, true ); + + connect( m_fontCombo, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_boldCheck, SIGNAL( stateChanged( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_italicCheck, SIGNAL( stateChanged( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_fontSize, SIGNAL( valueChanged( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_textPosition, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_textAlignment, SIGNAL( activated( int ) ), this, SLOT( valueChanged( int ) ) ); + connect( m_textOffset, SIGNAL( valueChanged( double ) ), this, SLOT( valueChanged( double ) ) ); + connect( m_textEditor, SIGNAL( returnPressed() ), this, SLOT( accept() ) ); + connect( m_textEditor, SIGNAL( textChanged( const QString& ) ), this, SLOT( textChanged( const QString& ) ) ); + connect( m_editBasePath, SIGNAL( clicked() ), this, SLOT( editBasePath() ) ); + connect( m_convertToShapes, SIGNAL( clicked() ), this, SLOT( convertToShapes() ) ); + connect( this, SIGNAL( cancelClicked() ), this, SLOT( cancel() ) ); + + setMainWidget( base ); + setFixedSize( baseSize() ); +} + +VTextOptionsWidget::~VTextOptionsWidget() +{ +} + +void +VTextOptionsWidget::valueChanged( int ) +{ + m_fontCombo->setBold( m_boldCheck->isChecked() ); + m_fontCombo->setItalic( m_italicCheck->isChecked() ); + + m_textEditor->setFont( QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() ) ); + + if( m_tool && isVisible() ) + m_tool->textChanged(); +} + +void +VTextOptionsWidget::valueChanged( double ) +{ + if( m_tool && isVisible() ) + m_tool->textChanged(); +} + +void +VTextOptionsWidget::accept() +{ + if( m_tool ) + m_tool->accept(); + hide(); +} + +void +VTextOptionsWidget::cancel() +{ + if( m_tool ) + m_tool->cancel(); +} + +void +VTextOptionsWidget::textChanged( const QString& ) +{ + if( m_tool && isVisible() ) + m_tool->textChanged(); +} + +void +VTextOptionsWidget::editBasePath() +{ + if( m_tool ) + m_tool->editBasePath(); +} + +void +VTextOptionsWidget::convertToShapes() +{ + if( m_tool ) + m_tool->convertToShapes(); +} + +void +VTextOptionsWidget::setFont( const QFont& font ) +{ + m_fontCombo->setCurrentText( font.family() ); + + m_boldCheck->setChecked( font.bold() ); + + m_italicCheck->setChecked( font.italic() ); + + m_fontSize->setValue( font.pointSize() ); + + m_fontCombo->setBold( m_boldCheck->isChecked() ); + m_fontCombo->setItalic( m_italicCheck->isChecked() ); + + m_textEditor->setFont( QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() ) ); +} + +QFont VTextOptionsWidget::font() +{ + return QFont( m_fontCombo->currentText(), m_fontSize->value(), ( m_boldCheck->isChecked() ? 75 : 50 ), m_italicCheck->isChecked() ); +} + +void +VTextOptionsWidget::setText( const QString& text ) +{ + m_textEditor->setText( text ); +} + +QString VTextOptionsWidget::text() +{ + return m_textEditor->text(); +} + +void +VTextOptionsWidget::setPosition( VText::Position position ) +{ + m_textPosition->setCurrentItem( position ); +} + +VText::Position VTextOptionsWidget::position() +{ + return ( VText::Position ) m_textPosition->currentItem(); +} + +void +VTextOptionsWidget::setAlignment( VText::Alignment alignment ) +{ + m_textAlignment->setCurrentItem( alignment ); +} + +VText::Alignment VTextOptionsWidget::alignment() +{ + return ( VText::Alignment ) m_textAlignment->currentItem(); +} + +void +VTextOptionsWidget::setOffset( double offset ) +{ + if( offset < 0.0 ) offset = 0.0; + if( offset > 100.0 ) offset = 100.0; + + m_textOffset->setValue( offset ); +} +double +VTextOptionsWidget::offset() +{ + return m_textOffset->value(); +} + +void +VTextOptionsWidget::setUseShadow( bool state ) +{ + m_shadow->setUseShadow( state ); +} + +bool VTextOptionsWidget::useShadow() +{ + return m_shadow->useShadow(); +} + +void +VTextOptionsWidget::setShadow( int angle, int distance, bool translucent ) +{ + m_shadow->setShadowValues( angle, distance, translucent ); +} + +bool VTextOptionsWidget::translucentShadow() +{ + return m_shadow->isTranslucent(); +} + +int +VTextOptionsWidget::shadowAngle() +{ + return m_shadow->shadowAngle(); +} + +int +VTextOptionsWidget::shadowDistance() +{ + return m_shadow->shadowDistance(); +} + +void +VTextOptionsWidget::initialize( VObject &text ) +{ + if( m_tool ) + m_tool->visit( text ); +} + +VTextTool::VTextTool( KarbonView *view ) + : VTool( view, "tool_text" ) +{ + m_optionsWidget = new VTextOptionsWidget( this, 0L ); + m_text = 0L; + m_editedText = 0L; + registerTool( this ); + m_cursor = new QCursor( VCursor::createCursor( VCursor::CrossHair ) ); +} + +VTextTool::~VTextTool() +{ + delete m_optionsWidget; + delete m_editedText; + delete m_cursor; +} + +QString VTextTool::contextHelp() +{ + QString s = i18n( "<qt><b>Text Tool</b><br>" ); + s += i18n("<i>Click</i> on document to place horizontal text.<br>" ); + s += i18n("<i>Click and drag</i> in document to place directional text.<br>" ); + s += i18n("<i>Click</i> on a selected path object to place text along its outline.<br>" ); + s += i18n("<i>Click</i> on a selected text object to change it.<br></qt>" ); + + return s; +} + +void +VTextTool::activate() +{ + VTool::activate(); + view()->statusMessage()->setText( i18n( "Text Tool" ) ); + view()->setCursor( *m_cursor ); + + m_creating = true; + m_text = 0L; + delete m_editedText; + m_editedText = 0L; +} + +void +VTextTool::deactivate() +{ +} + +void +VTextTool::draw( VPainter* painter ) +{ + if( m_editedText ) + m_editedText->draw( painter, &m_editedText->boundingBox() ); +} + +void +VTextTool::drawPathCreation() +{ + VPainter * painter = view()->painterFactory()->editpainter(); + + painter->setZoomFactor( view()->zoom() ); + + painter->setRasterOp( Qt::NotROP ); + painter->newPath(); + painter->setPen( Qt::DotLine ); + painter->setBrush( Qt::NoBrush ); + + painter->moveTo( first() ); + painter->lineTo( m_last ); + painter->strokePath(); +} + +void +VTextTool::drawEditedText() +{ + if( m_editedText ) + view()->repaintAll( m_editedText->boundingBox() ); +} + +void +VTextTool::mouseButtonPress() +{ + m_last = first(); + drawPathCreation(); + m_stepwise = false; +} + +void +VTextTool::mouseButtonRelease() +{ + if( ! view() ) + return; + + VSelection* selection = view()->part()->document().selection(); + VObject* selObj = selection->objects().getFirst(); + + // initialize dialog with single selected object + if( selection->objects().count() == 1 && selObj->boundingBox().contains( last() ) ) + m_optionsWidget->initialize( *selObj ); + else + { + // use a default horizontal path when just clicking + VSubpath path( 0L ); + path.moveTo( first() ); + path.lineTo( KoPoint( first().x()+10, first().y() ) ); + + if( ! createText( path ) ) + return; + } + + if( dynamic_cast<VText*>( selObj ) && selObj->boundingBox().contains( last() ) ) + m_optionsWidget->setCaption( i18n( "Change Text") ); + else + m_optionsWidget->setCaption( i18n( "Insert Text") ); + + m_optionsWidget->show(); +} + +void +VTextTool::mouseDrag() +{ + drawPathCreation(); + + if( m_stepwise && shiftPressed() ) + { + KoPoint act = last(); + KoPoint dst = act - first(); + + double angle = atan2( dst.y(), dst.x() ); + if( angle < 0 ) + angle += VGlobal::twopi; + + // calculate previuos and next modulo 45 degree step + double prevStep = angle - fmod( angle, VGlobal::pi_2 / 2.0f ); + double nextStep = prevStep + VGlobal::pi_2 / 2.0f; + // calculate distance between first and last point + double length = sqrt( dst.x()*dst.x() + dst.y()*dst.y() ); + + // use nearest step + if( angle - prevStep < nextStep - angle ) + { + m_last.setX( first().x() + length * cos( prevStep ) ); + m_last.setY( first().y() + length * sin( prevStep ) ); + } + else + { + m_last.setX( first().x() + length * cos( nextStep ) ); + m_last.setY( first().y() + length * sin( nextStep ) ); + } + } + else + m_last = last(); + + drawPathCreation(); +} + +void +VTextTool::mouseDragRelease() +{ + drawPathCreation(); + + if( m_creating && m_editedText ) + { + drawEditedText(); + delete m_editedText; + m_editedText = 0L; + } + + // use dragged path to create text along + VSubpath path( 0L ); + path.moveTo( first() ); + path.lineTo( m_last ); + + if( createText( path ) ) + { + m_optionsWidget->setCaption( i18n( "Insert Text") ); + m_optionsWidget->show(); + } +} + +bool +VTextTool::createText( VSubpath &path ) +{ + // no original text is used + m_text = 0L; + delete m_editedText; + + m_editedText = new VText( m_optionsWidget->font(), path, m_optionsWidget->position(), m_optionsWidget->alignment(), m_optionsWidget->text() ); + + if( ! m_editedText ) + return false; + + m_editedText->setState( VObject::edit ); + +#ifdef HAVE_KARBONTEXT + m_editedText->traceText(); +#endif + + // yes, we are creating a new text object + m_creating = true; + + return true; +} + +void +VTextTool::textChanged() +{ + if( !m_editedText ) + return; + + if( !m_creating && m_text && m_text->state() != VObject::hidden ) + { + // hide the original text if we are changing it + m_text->setState( VObject::hidden ); + view()->repaintAll( m_text->boundingBox() ); + } + else + view()->repaintAll( m_editedText->boundingBox() ); + + m_editedText->setText( m_optionsWidget->text() ); + m_editedText->setFont( m_optionsWidget->font() ); + m_editedText->setPosition( m_optionsWidget->position() ); + m_editedText->setAlignment( m_optionsWidget->alignment() ); + m_editedText->setOffset( 0.01 * m_optionsWidget->offset() ); +#ifdef HAVE_KARBONTEXT + m_editedText->traceText(); +#endif + + drawEditedText(); +} + +void +VTextTool::accept() +{ + if( !m_editedText ) + return; + + VTextCmd* cmd; + + if( !m_creating ) + { + cmd = new VTextCmd( + &view()->part()->document(), + i18n( "Change Text" ), + m_text, + m_editedText->font(), + m_editedText->basePath(), + m_editedText->position(), + m_editedText->alignment(), + m_editedText->offset(), + m_editedText->text(), + m_optionsWidget->useShadow(), + m_optionsWidget->shadowAngle(), + m_optionsWidget->shadowDistance(), + m_optionsWidget->translucentShadow() ); + } + else + { + VText *newText = m_editedText->clone(); + newText->setUseShadow( m_optionsWidget->useShadow() ); + newText->setShadow( m_optionsWidget->shadowAngle(), m_optionsWidget->shadowDistance(), m_optionsWidget->translucentShadow() ); + + cmd = new VTextCmd( + &view()->part()->document(), + i18n( "Insert Text" ), + newText ); + + delete m_editedText; + m_editedText = 0L; + } + + view()->part()->addCommand( cmd, true ); + view()->part()->repaintAllViews(); + m_creating = false; +} + +void +VTextTool::cancel() +{ + if( m_text ) + { + // show original text if we canceled changing it + m_text->setState( VObject::selected ); + view()->repaintAll( m_text->boundingBox() ); + } + else + drawPathCreation(); + + delete m_editedText; + m_editedText = 0L; +} + +void +VTextTool::editBasePath() +{ + if( !m_editedText ) + return; + + view()->part()->document().selection()->clear(); + view()->part()->document().selection()->append( &m_editedText->basePath() ); + view()->part()->repaintAllViews(); +} + +void +VTextTool::convertToShapes() +{ + if( !m_text ) + return; + + VTextToCompositeCmd* cmd = new VTextToCompositeCmd( + &view()->part()->document(), + i18n( "Text Conversion" ), + m_text ); + + view()->part()->addCommand( cmd, true ); + + m_creating = false; + + delete m_editedText; + + m_text = 0L; + m_editedText = 0L; +} + +void +VTextTool::visitVPath( VPath& composite ) +{ + if( composite.paths().count() == 0 ) + return; + + if( createText( *composite.paths().getFirst() ) ) + drawEditedText(); +} + +void +VTextTool::visitVSubpath( VSubpath& path ) +{ + if( createText( path ) ) + drawEditedText(); +} + +void +VTextTool::visitVText( VText& text ) +{ + m_text = &text; + delete m_editedText; + m_editedText = text.clone(); + + m_optionsWidget->setFont( text.font() ); + m_optionsWidget->setText( text.text() ); + m_optionsWidget->setPosition( text.position() ); + m_optionsWidget->setAlignment( text.alignment() ); + m_optionsWidget->setOffset( text.offset() * 100.0 ); + m_optionsWidget->setUseShadow( text.useShadow() ); + m_optionsWidget->setShadow( text.shadowAngle(), text.shadowDistance(), text.translucentShadow() ); + m_creating = false; + m_text->setState( VObject::hidden ); + m_editedText->setState( VObject::edit ); +} + +VTextTool::VTextCmd::VTextCmd( VDocument* doc, const QString& name, VText* text ) + : VCommand( doc, name, "14_text" ), m_text( text ) +{ + m_textModifications = 0L; + + m_executed = false; +} + +VTextTool::VTextCmd::VTextCmd( VDocument* doc, const QString& name, VText* text, + const QFont &newFont, const VSubpath& newBasePath, VText::Position newPosition, VText::Alignment newAlignment, double newOffset, const QString& newText, + bool newUseShadow, int newShadowAngle, int newShadowDistance, bool newTranslucentShadow ) + : VCommand( doc, name, "14_text" ), m_text( text ) +{ + m_textModifications = new VTextModifPrivate(); + m_textModifications->newFont = newFont; + m_textModifications->oldFont = text->font(); + m_textModifications->newBasePath = newBasePath; + m_textModifications->oldBasePath = text->basePath(); + m_textModifications->newPosition = newPosition; + m_textModifications->oldPosition = text->position(); + m_textModifications->newAlignment = newAlignment; + m_textModifications->oldAlignment = text->alignment(); + m_textModifications->newOffset = newOffset; + m_textModifications->oldOffset = text->offset(); + m_textModifications->newText = newText; + m_textModifications->oldText = text->text(); + m_textModifications->newUseShadow = newUseShadow; + m_textModifications->oldUseShadow = text->useShadow(); + m_textModifications->newShadowAngle = newShadowAngle; + m_textModifications->oldShadowAngle = text->shadowAngle(); + m_textModifications->newShadowDistance = newShadowDistance; + m_textModifications->oldShadowDistance = text->shadowDistance(); + m_textModifications->newTranslucentShadow = newTranslucentShadow; + m_textModifications->oldTranslucentShadow = text->translucentShadow(); + + m_executed = false; +} + +VTextTool::VTextCmd::~VTextCmd() +{ + delete m_textModifications; +} + +void +VTextTool::VTextCmd::execute() +{ + if( !m_text ) + return; + + if( !m_textModifications ) + { + if( m_text->state() == VObject::deleted ) + m_text->setState( VObject::normal ); + else + { + m_text->setState( VObject::normal ); + document()->append( m_text ); + document()->selection()->clear(); + document()->selection()->append( m_text ); + } + } + else + { + m_text->setFont( m_textModifications->newFont ); + m_text->setBasePath( m_textModifications->newBasePath ); + m_text->setPosition( m_textModifications->newPosition ); + m_text->setAlignment( m_textModifications->newAlignment ); + m_text->setOffset( m_textModifications->newOffset ); + m_text->setText( m_textModifications->newText ); + m_text->setUseShadow( m_textModifications->newUseShadow ); + m_text->setShadow( m_textModifications->newShadowAngle, m_textModifications->newShadowDistance, m_textModifications->newTranslucentShadow ); + +#ifdef HAVE_KARBONTEXT + m_text->traceText(); +#endif + + m_text->setState( VObject::normal ); + } + + m_executed = true; + + setSuccess( true ); +} + +void +VTextTool::VTextCmd::unexecute() +{ + if( !m_text ) + return; + + if( !m_textModifications ) + { + document()->selection()->take( *m_text ); + m_text->setState( VObject::deleted ); + } + else + { + m_text->setFont( m_textModifications->oldFont ); + m_text->setBasePath( m_textModifications->oldBasePath ); + m_text->setPosition( m_textModifications->oldPosition ); + m_text->setAlignment( m_textModifications->oldAlignment ); + m_text->setOffset( m_textModifications->oldOffset ); + m_text->setText( m_textModifications->oldText ); + m_text->setUseShadow( m_textModifications->oldUseShadow ); + m_text->setShadow( m_textModifications->oldShadowAngle, m_textModifications->oldShadowDistance, m_textModifications->oldTranslucentShadow ); + +#ifdef HAVE_KARBONTEXT + m_text->traceText(); +#endif + + m_text->setState( VObject::normal ); + } + + m_executed = false; + + setSuccess( false ); +} + +VTextTool::VTextToCompositeCmd::VTextToCompositeCmd( VDocument* doc, const QString& name, VText* text ) + : VCommand( doc, name, "14_text" ), m_text( text ), m_group( 0L ), m_executed( false ) +{ +} + +VTextTool::VTextToCompositeCmd::~VTextToCompositeCmd() +{ +} + +void +VTextTool::VTextToCompositeCmd::execute() +{ + if( !m_text ) + return; + + if( !m_group ) + { + m_group = m_text->toVGroup(); + document()->append( m_group ); + } + + m_text->setState( VObject::deleted ); + m_group->setState( VObject::normal ); + document()->selection()->clear(); + document()->selection()->append( m_group ); + + m_executed = true; + + setSuccess( true ); +} + +void +VTextTool::VTextToCompositeCmd::unexecute() +{ + if( !m_text ) + return; + + m_text->setState( VObject::normal ); + + document()->selection()->take( *m_group ); + + m_group->setState( VObject::deleted ); + + m_executed = false; + + setSuccess( false ); +} + +bool +VTextTool::showDialog() const +{ + VSelection* selection = view()->part()->document().selection(); + + // initialize dialog with single selected object + if( selection->objects().count() == 1 ) + m_optionsWidget->initialize( *selection->objects().getFirst()); + else + return false; + + if( dynamic_cast<VText*>( selection->objects().getFirst() ) ) + m_optionsWidget->setCaption(i18n( "Change Text") ); + else + m_optionsWidget->setCaption(i18n( "Insert Text") ); + + m_optionsWidget->show(); + return true; +} + +void +VTextTool::mouseDragShiftPressed() +{ + m_stepwise = true; + mouseDrag(); +} + +void +VTextTool::mouseDragShiftReleased() +{ + m_stepwise = false; + mouseDrag(); +} + +void +VTextTool::setup( KActionCollection *collection ) +{ + m_action = static_cast<KRadioAction *>(collection -> action( name() ) ); + + if( m_action == 0 ) + { + m_action = new KRadioAction( i18n( "Text Tool" ), "14_text", Qt::SHIFT+Qt::Key_T, this, SLOT( activate() ), collection, name() ); + m_action->setToolTip( i18n( "Text Tool" ) ); + m_action->setExclusiveGroup( "misc" ); + //m_ownAction = true; + } +} + +#include "vtexttool.moc" + diff --git a/karbon/tools/vtexttool.h b/karbon/tools/vtexttool.h new file mode 100644 index 00000000..add0dd35 --- /dev/null +++ b/karbon/tools/vtexttool.h @@ -0,0 +1,287 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTEXTTOOL_H__ +#define __VTEXTTOOL_H__ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kdialogbase.h> + +#include "qframe.h" +#include "qgroupbox.h" +#include "qcombobox.h" + +#include "vcommand.h" +#include "vtext.h" +#include "vtool.h" + +class KFontCombo; +class KIntNumInput; +class QCheckBox; +class QLineEdit; +class QPushButton; +class QTabWidget; +class ShadowWidget; +class VTextTool; +class QCursor; + +class ShadowPreview : public QWidget +{ + Q_OBJECT + +public: + ShadowPreview( ShadowWidget* parent ); + ~ShadowPreview(); + +signals: + void changed( int angle, int distance, bool ); + +protected: + virtual void mouseReleaseEvent( QMouseEvent* ); + virtual void paintEvent( QPaintEvent* ); + +private: + ShadowWidget* m_parent; +}; + + +class ShadowWidget : public QGroupBox +{ + Q_OBJECT + +public: + ShadowWidget( QWidget* parent, const char* name, int angle, int distance, bool translucent ); + ~ShadowWidget(); + + void setUseShadow( bool use ); + bool useShadow(); + void setShadowAngle( int angle ); + int shadowAngle(); + void setShadowDistance( int distance ); + int shadowDistance(); + void setTranslucent( bool translucent ); + bool isTranslucent(); + +public slots: + void setShadowValues( int angle, int distance, bool translucent ); + void updatePreview( int ); + void updatePreview(); + +protected: + QCheckBox* m_useShadow; + KIntNumInput* m_angle; + KIntNumInput* m_distance; + QCheckBox* m_translucent; + ShadowPreview* m_preview; +}; + + +class VTextOptionsWidget : public KDialogBase +{ + Q_OBJECT + +public: + VTextOptionsWidget( VTextTool* tool, QWidget *parent ); + ~VTextOptionsWidget(); + + void setFont( const QFont& font ); + QFont font(); + void setText( const QString& text ); + QString text(); + void setPosition( VText::Position position ); + VText::Position position(); + void setAlignment( VText::Alignment alignment ); + VText::Alignment alignment(); + void setOffset( double offset ); + double offset(); + void setUseShadow( bool state ); + bool useShadow(); + void setShadow( int angle, int distance, bool translucent ); + bool translucentShadow(); + int shadowAngle(); + int shadowDistance(); + +public slots: + void valueChanged( int ); + void valueChanged( double ); + void accept(); + void cancel(); + void textChanged( const QString& ); + void editBasePath(); + void convertToShapes(); + void initialize( VObject &text ); + +protected: + QTabWidget* m_tabWidget; + KFontCombo* m_fontCombo; + QCheckBox* m_boldCheck; + QCheckBox* m_italicCheck; + KIntNumInput* m_fontSize; + QLineEdit* m_textEditor; + ShadowWidget* m_shadow; + QComboBox* m_textAlignment; + QComboBox* m_textPosition; + QPushButton* m_editBasePath; + QPushButton* m_convertToShapes; + KDoubleNumInput* m_textOffset; + VTextTool* m_tool; +}; + + +class VTextTool : public VTool, public VVisitor +{ +public: + VTextTool( KarbonView *view ); + ~VTextTool(); + + virtual void setup (KActionCollection *collection ); + virtual QString uiname() { return i18n( "Text Tool" ); } + + virtual QString contextHelp(); + virtual bool showDialog() const; + + virtual void activate(); + virtual void deactivate(); + + virtual void mouseButtonPress(); + virtual void mouseButtonRelease(); + virtual void mouseDrag(); + virtual void mouseDragRelease(); + virtual void textChanged(); + virtual void accept(); + virtual void cancel(); + virtual void editBasePath(); + virtual void convertToShapes(); + + virtual void visitVPath( VPath& composite ); + virtual void visitVDocument( VDocument& ) + {} + + virtual void visitVGroup( VGroup& ) + {} + + virtual void visitVLayer( VLayer& ) + {} + + virtual void visitVSubpath( VSubpath& path ); + virtual void visitVText( VText& text ); + + virtual void draw( VPainter* painter ); + +protected: + virtual void mouseDragShiftPressed(); + virtual void mouseDragShiftReleased(); + +private: + class VTextCmd : public VCommand + { + public: + VTextCmd( VDocument* doc, const QString& name, VText* text ); + VTextCmd( VDocument* doc, const QString& name, VText* text, + const QFont &newFont, const VSubpath& newBasePath, VText::Position newPosition, VText::Alignment newAlignment, double newOffset, const QString& newText, + bool newUseShadow, int newShadowAngle, int newShadowDistance, bool newTranslucentShadow ); + virtual ~VTextCmd(); + + virtual void execute(); + virtual void unexecute(); + virtual bool isExecuted() + { + return m_executed; + } + virtual bool changesSelection() const { return true; } + + private: + class VTextModifPrivate + { + public: + VTextModifPrivate() : oldBasePath( 0L ), newBasePath( 0L ) + {} + + QFont oldFont; + QFont newFont; + VSubpath oldBasePath; + VSubpath newBasePath; + VText::Position oldPosition; + VText::Position newPosition; + VText::Alignment oldAlignment; + VText::Alignment newAlignment; + double oldOffset; + double newOffset; + QString oldText; + QString newText; + bool oldUseShadow; + bool newUseShadow; + int oldShadowAngle; + int newShadowAngle; + int oldShadowDistance; + int newShadowDistance; + bool oldTranslucentShadow; + bool newTranslucentShadow; + }; + + VText* m_text; + bool m_executed; + VTextModifPrivate* m_textModifications; + }; + + class VTextToCompositeCmd : public VCommand + { + public: + VTextToCompositeCmd( VDocument* doc, const QString& name, VText* text ); + virtual ~VTextToCompositeCmd(); + + virtual void execute(); + virtual void unexecute(); + virtual bool isExecuted() + { + return m_executed; + } + + private: + VText* m_text; + VGroup* m_group; + bool m_executed; + }; + + void drawPathCreation(); + void drawEditedText(); + + /** + * Creates new temporary text object along given path for displaying. + * + * @param path the path to create the text along + */ + bool createText( VSubpath &path ); + + VTextOptionsWidget* m_optionsWidget; + KoPoint m_last; + VText* m_text; + VText* m_editedText; + bool m_creating; + // are we dragging in 45 degree steps? + bool m_stepwise; + QCursor* m_cursor; +}; + +#endif + diff --git a/karbon/usablity-review.txt b/karbon/usablity-review.txt new file mode 100644 index 00000000..5d2eb8b4 --- /dev/null +++ b/karbon/usablity-review.txt @@ -0,0 +1,216 @@ +Since I think the following link is closely related, I am including it here : + +http://dan.ostrowski.cc/suggestions.html + +Rob Buis <buis@kde.org> +17-12-2003 + + +On 27-sept 2003 I did a usabiltiy review of karbon. +This is during the feature and message freeze of KOffice (pending the 1.3 +release) so many of these issues will probably have to wait. Hence this +document in CVS. + +Issues are written down, and if possible to do without a ui file, a proposal +is made. +Naturally this file does not cover each part; items will be added by me when +feedback seems positive and time permits. + +Please remove this file (or individual points from this file) when all stuff +has been done/fiexed (which I hope is fast :) + +Thomas Zander <zander@kde.org> + + + +Starting up I notice that the toolbars are not persistent; the 'Tools' bar +was left floating by me last time, now its docked at the top again. +Since that makes the whole top-line of bars quite large I do think that +the tools bar has to go to the left by default. And the toolbars should +be persistent naturally. + +Toolbar 'Tools' +=============== +The toolbar is used to select the main tools by clicking on buttons (more +radio buttons actually; since you keep it selected when you click it). +To select extra options you click on the icon again, which brings up an +options window. +bug: the options window of the 'select tool' (top left) has a title 'insert star'. + +First problem I see is that it is hard to see which tool is currently selected, +while this might be a problem in the style (KDE3.2 default) there is another +problem that makes this problem really a problem instead of just an annoyance. +It is not obvious that clicking on an already clicked item brings up a dialog, +it is annoying to get that dialog if you just clicked the item to make sure +you clicked it. +Another bug makes it even worse; the '14' icon is clickable but does not notify +the software that the formerly selected tool is not selected anymore. Selecting +the formerly selected tool again brings up the options dialog again. + +I suggest to move the options dialog to a dockable toolbar which is brought to +front, or simply displayed when dubble clicked. Notice that dubble clicking is +different from the click twice action that happens now. + +Suggestion2: +Add keyboard shortcuts to the buttons and show them in the tooltips. The keys +should be single key (no modifier) shortcuts. +Suggestion3: +Add a new tool called a 'line' which creates a single non-closed line (and no +options to make it curved) and put that in the place of the annoying '14'. +Suggestion4: +Make 'ESC' select the 'Select tool' + + + +Tool: Select tool +================= +With the select tool you can select elements like individual starts or groups. +The way it currently works is that it takes the click and selects the first +object that it falls into based on the algoritm of the complete square that +contains the top left to the bottom right coordinate. +selection can only be done via a square and all objects that have a presence +in that square are selected. +The problems I found are; + +When you have multiple objects you tend to select the wrong one. +It is impossible to add or subtract objects from the current selection. +It is impossible to select 3 objects from a four-in-a-row where the +unselects is not one of the outside objects. +It is impossible to select an object that is completely inside another. + +A perfect solution would: +* make the 'hit area' based more on the outside of the shape. +A line should not be selected when clicked more then pixels next to it. +Text should be selected when clicked in the white area of a 'D' + +* Select extra objects when CTRL is used to select them. +* Select extra objects that occupy the same spot (behind each other) +when pressing CTRL and ALT +* Select an object that is 1 layer deeper (behind the currently selected one) +and unselect the current one by clicking CTRL and SHIFT. + +* An extra selection tool would be able to draw freehand on screen and all +stuff inside that freehand selection would be selected. + +* When noting is selected and I point and drag an object (using the modifiers +from above) directly drag that object. + +* Using 'shift' while dragging for a position for the text snaps the angle to +an angle mod(45) i.e. 0,45,90,... + +Notice that the selection options proposed are taken from KWord. + +Tool: Select Nodes Tool +======================= +The goal is to select and modify individual nodes. +With the current approuch you have to select an individual node by dragging a +selection over it for the object you want to modify to show all of its nodes. +Following that you can find the node you want to edit and select that one, +again dragging a selection box over that node. + +With the current approuch it is not possible to; +quickly find out which nodes exist on an object; on objects that don't have +many nodes you quickly miss the nodes. On top of that alternative +applications allow the user to select a line with a single click. That user +will take a number of tries to find a node to select and will probably not +learn this approuch for quite some time. +Selecting a node before you can edit it is also counter intuitive; I found +myself clicking and dragging a node some times, only to see another node moving +that I had selected before. + +I suggest: +* Allow the user to select an object (to show all of its nodes) by clicking on +a line; of the object. +* If one (or more) objects were selected when the select nodes tool is invoked +make those objects selected directly and draw all their nodes. Possibly using +an algoritm to not draw 'hidden' nodes. Hidden means ones that lie underneath +other objects. +* When a click is made missing all objects; don't unselect the object (thus +removing node previews) + +* When a node itself is clicked on a selected object, select that one. +* When a node itself is clicked and dragged on a selected object, drag that one. +* Use the node selection algoritm that are the same as the object selection +algorithm described above. +* Allow a node to gain a knot when ctrl is used to drag it +* Using 'shift' while dragging for a position for the text snaps the angle to +an angle mod(45) i.e. 0,45,90,... + + + +Tool: Rotate +============ + +I don't get this one; there is a center 'dot' painted that stuff moves around, +but that dot also moves when I rotate. That should not be possible... +I also did not find a way to set the center point.. + + +Tool: Shear Tool +=============== +Is this suppost to actually do something? + + +Tool: Text tool +=============== +After I found out I could click twice, I understood it a bit more; but this one +is still largely a mystory to me.. + +I suggest: +* Single click makes a horizontal text entry; drawing a horizontal line in +light blue (for example). +* Using 'shift' while dragging for a position for the text snaps the angle to +an angle mod(45) i.e. 0,45,90,... +* Popup a dialog, or allow in line editing as soon as a position is determined +by the click or drag +* Put a default text in the dialog when the application starts up so the first +drag shows that text. + + +Tool: Pattern tool +================== +As soon as I find out what it does.. + + +Tool: Zoom +============== +Please use 'alt' to zoom out again... + + +Colors (in tools toolbar) +======================== +Currently you have to double click to get the color dialog. Make that use the +KDE double click policy. +The 'Stroke' tab is inacurately named since it also contains info on gradients. +I suggest renaming it to 'Outline' + +Overview dock; +============== +it should be possible to make that tool larger, and it should really start larger by +default. + +Layers: +Put tooltips on +- the checkbox by a layer (what is it for anyway) +- The lock column (or each lock if you can't do it per column) +- The visible column. +Don't blank the preview of the object when it is set to non visible; make it +grayed out. + +This looks really unfinished right now so I won't go into this and trample +someones unfinished work. + + + +General content area +==================== +There are keyboard navigation features added that are not quite the same as +what artists from other packages are expecting. +- Add 'del' to delete an object +- allow 'SHIFT' arrow to move the item 1/4th of te distance. +- Allow shift dragging to drag an item across a 45 degrees line. So only +horizontally, vertically and the 45 and 135 degrees axis. +- Allow shift scaling to keep aspect ratio. +- Allow ctrl scaling to scale around the center instead of against the +other edge + diff --git a/karbon/visitors/Makefile.am b/karbon/visitors/Makefile.am new file mode 100644 index 00000000..60bc3caa --- /dev/null +++ b/karbon/visitors/Makefile.am @@ -0,0 +1,28 @@ +INCLUDES = \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../tools \ + -I$(srcdir)/../render \ + $(LIBFREETYPE_CFLAGS) $(all_includes) + +noinst_LTLIBRARIES = libkarbonvisitors.la + +noinst_HEADERS = \ + vselectnodes.h \ + vselectobjects.h \ + vdrawselection.h \ + vselectiondesc.h \ + vtransformnodes.h \ + vcomputeboundingbox.h + +libkarbonvisitors_la_SOURCES = \ + vselectnodes.cc \ + vselectobjects.cc \ + vdrawselection.cc \ + vselectiondesc.cc \ + vtransformnodes.cc \ + vcomputeboundingbox.cc + +libkarbonvisitors_la_METASOURCES = \ + AUTO diff --git a/karbon/visitors/vcomputeboundingbox.cc b/karbon/visitors/vcomputeboundingbox.cc new file mode 100644 index 00000000..e303a2f9 --- /dev/null +++ b/karbon/visitors/vcomputeboundingbox.cc @@ -0,0 +1,110 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vcomputeboundingbox.h" +#include "vdocument.h" +#include "vlayer.h" +#include "vgroup.h" +#include "vcomposite.h" +#include "vtext.h" +#include "vimage.h" + +VComputeBoundingBox::VComputeBoundingBox( bool omitHidden ) +: m_omitHidden( omitHidden ) +{ +} + +void +VComputeBoundingBox::visitVDocument( VDocument& document ) +{ + VLayerListIterator itr( document.layers() ); + + for( ; itr.current(); ++itr ) + { + if( itr.current()->state() == VObject::deleted ) + continue; + // do not use hidden layers + if( m_omitHidden && ! isVisible( itr.current() ) ) + continue; + itr.current()->accept( *this ); + } +} + +void +VComputeBoundingBox::visitVLayer( VLayer& layer ) +{ + VObjectListIterator itr( layer.objects() ); + + for( ; itr.current(); ++itr ) + { + if( itr.current()->state() == VObject::deleted ) + continue; + // do not export hidden objects + if( m_omitHidden && ! isVisible( itr.current() ) ) + continue; + itr.current()->accept( *this ); + } +} + +void +VComputeBoundingBox::visitVGroup( VGroup& group ) +{ + VObjectListIterator itr( group.objects() ); + + for( ; itr.current(); ++itr ) + { + if( itr.current()->state() == VObject::deleted ) + continue; + // do not use hidden child objects + if( m_omitHidden && ! isVisible( itr.current() ) ) + continue; + itr.current()->accept( *this ); + } +} + +void +VComputeBoundingBox::visitVPath( VPath& composite ) +{ + m_boundingBox |= composite.boundingBox(); +} + +void +VComputeBoundingBox::visitVText( VText& text ) +{ + m_boundingBox |= text.boundingBox(); +} + +void +VComputeBoundingBox::visitVImage( VImage& img ) +{ + m_boundingBox |= img.boundingBox(); +} + +bool +VComputeBoundingBox::isVisible( const VObject* object ) const +{ + return object->state() != VObject::hidden && object->state() != VObject::hidden_locked; +} + +const KoRect& +VComputeBoundingBox::boundingRect() const +{ + return m_boundingBox; +} diff --git a/karbon/visitors/vcomputeboundingbox.h b/karbon/visitors/vcomputeboundingbox.h new file mode 100644 index 00000000..437b1125 --- /dev/null +++ b/karbon/visitors/vcomputeboundingbox.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net> + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCOMPUTEBOUNDINGBOX_H__ +#define __VCOMPUTEBOUNDINGBOX_H__ + +#include "KoRect.h" +#include "vvisitor.h" + +class VDocument; +class VLayer; +class VGroup; +class VPath; +class VText; +class VImage; + +/** + * This visitor visits objects and calculates the combined bounding box of the + * objects and their child objects. + */ +class VComputeBoundingBox : public VVisitor +{ +public: + VComputeBoundingBox( bool omitHidden = false ); + + virtual void visitVDocument( VDocument& document ); + virtual void visitVLayer( VLayer& layer ); + virtual void visitVGroup( VGroup& group ); + virtual void visitVPath( VPath& composite ); + virtual void visitVText( VText& text ); + virtual void visitVImage( VImage& img ); + + const KoRect& boundingRect() const; +private: + bool isVisible( const VObject* object ) const; + + KoRect m_boundingBox; + bool m_omitHidden; +}; + +#endif // __VCOMPUTEBOUNDINGBOX_H__ + diff --git a/karbon/visitors/vdrawselection.cc b/karbon/visitors/vdrawselection.cc new file mode 100644 index 00000000..ad597027 --- /dev/null +++ b/karbon/visitors/vdrawselection.cc @@ -0,0 +1,174 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vdrawselection.h" +#include "vcomposite.h" +#include "vsegment.h" +#include "vcolor.h" +#include "vstroke.h" +#include "vpainter.h" +#include "vpath.h" + +void +VDrawSelection::visitVPath( VPath &composite ) +{ + if( + composite.state() == VObject::deleted || + composite.state() == VObject::hidden || + composite.state() == VObject::hidden_locked ) + { + return; + } + + + m_painter->save(); + m_painter->setPen( Qt::SolidLine ); + + const bool editnodes = composite.state() == VObject::edit && m_nodeediting; + + VSubpathListIterator itr( composite.paths() ); + + if( + composite.state() == VObject::selected || + editnodes ) + { + // paint fill: + m_painter->newPath(); + + if( editnodes ) + m_painter->setRasterOp( Qt::XorROP ); + + m_painter->setPen( editnodes ? Qt::yellow : Qt::blue ); + m_painter->setBrush( Qt::NoBrush ); + + for( itr.toFirst(); itr.current(); ++itr ) + { + VSubpathIterator jtr( *( itr.current() ) ); + + for( ; jtr.current(); ++jtr ) + { + jtr.current()->draw( m_painter ); + } + + m_painter->strokePath(); + } + } + + // Draw nodes and control lines. + if( + composite.state() == VObject::selected || + editnodes ) + { + itr.toFirst(); + //++itr; // Skip "begin". + + for( ; itr.current(); ++itr ) + { + if( (*itr)->isEmpty() ) + continue; + VSubpathIterator jtr( *( itr.current() ) ); + //++jtr; + + for( ; jtr.current(); ++jtr ) + { + if( editnodes ) + m_painter->setRasterOp( Qt::XorROP ); + + VColor color; + color.set( 0.5, 0.5, 1.0 ); + + VStroke stroke( color ); + stroke.setLineWidth( 1.0 ); + + if( !editnodes ) + { + m_painter->setPen( stroke ); + m_painter->setPen( Qt::blue ); + } + else + m_painter->setPen( Qt::yellow ); + + m_painter->setBrush( Qt::NoBrush ); + + if( ( editnodes || composite.state() == VObject::selected && m_nodeediting ) && + jtr.current()->isCurve() ) + { + VSegment* curr = jtr.current(); + VSegment* next = curr->next(); + VSegment* prev = curr->prev(); + + // Draw control lines. + if ( curr->pointIsSelected( curr->degree()-2 ) || curr->knotIsSelected() + || ( next && next->isCurve() && next->pointIsSelected( 0 ) && curr->isSmooth() ) ) + { + m_painter->newPath(); + m_painter->moveTo( curr->point( curr->degree()-2 ) ); + m_painter->lineTo( curr->knot() ); + m_painter->strokePath(); + // Draw control node2: + m_painter->newPath(); + m_painter->setBrush( editnodes ? Qt::yellow : Qt::blue ); + m_painter->drawNode( curr->point( curr->degree()-2 ), m_nodeSize ); + m_painter->strokePath(); + } + + if ( prev && ( ( prev->knotIsSelected() || curr->pointIsSelected( 0 ) ) + || ( prev->isCurve() && prev->pointIsSelected( prev->degree()-2 ) && prev->isSmooth() ) ) ) + { + m_painter->newPath(); + m_painter->moveTo( prev->knot() ); + m_painter->lineTo( curr->point( 0 ) ); + m_painter->strokePath(); + // Draw control node1: + m_painter->newPath(); + m_painter->setBrush( editnodes ? Qt::yellow : Qt::blue ); + m_painter->drawNode( curr->point( 0 ), m_nodeSize ); + m_painter->strokePath(); + } + } + + // Draw knot. + m_painter->setPen( editnodes ? Qt::yellow : Qt::blue ); + + if( !m_nodeediting ) + m_painter->setBrush( Qt::blue ); + else if( jtr.current()->knotIsSelected() ) + m_painter->setBrush( editnodes ? Qt::yellow : Qt::blue ); + else + m_painter->setBrush( Qt::white ); + + m_painter->drawNode( jtr.current()->knot(), m_nodeSize ); + } + } + } + + // Draw center node. + if( composite.drawCenterNode() && composite.state() == VObject::selected && !m_nodeediting ) + { + m_painter->setPen( Qt::NoPen ); + m_painter->setBrush( Qt::blue.light() ); + m_painter->drawNode( composite.boundingBox().center(), m_nodeSize ); + } + + m_painter->restore(); + + setSuccess(); +} + diff --git a/karbon/visitors/vdrawselection.h b/karbon/visitors/vdrawselection.h new file mode 100644 index 00000000..535d9184 --- /dev/null +++ b/karbon/visitors/vdrawselection.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VDRAWSELECTION_H__ +#define __VDRAWSELECTION_H__ + +#include "vgroup.h" +#include "vvisitor.h" +#include <koffice_export.h> +/** + * Helper class to draw the outline of a composite path, including (?) + * optionally its bezier helper lines, depending on the state. + */ +class KARBONBASE_EXPORT VDrawSelection : public VVisitor +{ +public: + VDrawSelection( const VObjectList& selection, VPainter *painter, bool nodeediting = false, uint nodeSize = 2 ) + : m_selection( selection ), m_painter( painter ), m_nodeediting( nodeediting ), m_nodeSize( nodeSize ) {} + + virtual void visitVPath( VPath& composite ); + +private: + VObjectList m_selection; + VPainter *m_painter; + bool m_nodeediting; + uint m_nodeSize; +}; + +#endif + diff --git a/karbon/visitors/vselectiondesc.cc b/karbon/visitors/vselectiondesc.cc new file mode 100644 index 00000000..0036f31c --- /dev/null +++ b/karbon/visitors/vselectiondesc.cc @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vselectiondesc.h" +#include "vselection.h" +#include "vgroup.h" +#include "vtext.h" +#include "vimage.h" +#include "vcomposite.h" +#include <kdebug.h> +#include <klocale.h> + +void +VSelectionDescription::visitVSelection( VSelection& selection ) +{ + if( selection.objects().count() == 1 ) + VVisitor::visitVSelection( selection ); + else + m_desc = i18n( "One object", "%n objects", selection.objects().count() ); +} + +void +VSelectionDescription::visitVPath( VPath& composite ) +{ + m_desc = m_shortdesc = !composite.name().isEmpty() ? composite.name() : i18n( "path" ); +} + +void +VSelectionDescription::visitVGroup( VGroup &group ) +{ + m_desc = i18n( "One group, containing one object", "One group, containing %n objects", group.objects().count() ); + m_shortdesc = !group.name().isEmpty() ? group.name() : i18n( "group" ); +} + +void +VSelectionDescription::visitVText( VText &text ) +{ + m_desc = m_shortdesc = !text.name().isEmpty() ? text.name() : i18n( "text" ); +} + +void +VSelectionDescription::visitVImage( VImage &img ) +{ + m_desc = m_shortdesc = !img.name().isEmpty() ? img.name() : i18n( "image" ); +} + diff --git a/karbon/visitors/vselectiondesc.h b/karbon/visitors/vselectiondesc.h new file mode 100644 index 00000000..c019c107 --- /dev/null +++ b/karbon/visitors/vselectiondesc.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTIONDESC_H__ +#define __VSELECTIONDESC_H__ + +#include "vvisitor.h" +#include <qstring.h> +#include <koffice_export.h> +/** + * This visitors visits structures and tries to capture relevant object type info + * as text. There are two methods, one creates a large description like "(1 group, containing + * 2 objects)", and a short description giving object id, or if there is no object id just the + * object type, like group/path/text etc. + * + * These texts are primarily meant for statusbar messages and object trees. + */ +class KARBONBASE_EXPORT VSelectionDescription : public VVisitor +{ +public: + VSelectionDescription() { m_desc = ""; m_shortdesc = ""; } + + virtual void visitVSelection( VSelection& ); + virtual void visitVGroup( VGroup& ); + virtual void visitVPath( VPath& ); + virtual void visitVText( VText& ); + virtual void visitVImage( VImage& ); + + QString description() { return m_desc; } + QString shortDescription() { return m_shortdesc; } + +private: + QString m_desc; + QString m_shortdesc; +}; + +#endif + diff --git a/karbon/visitors/vselectnodes.cc b/karbon/visitors/vselectnodes.cc new file mode 100644 index 00000000..00f56de3 --- /dev/null +++ b/karbon/visitors/vselectnodes.cc @@ -0,0 +1,153 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vpath.h" +#include "vsegment.h" +#include "vselectnodes.h" +#include "vlayer.h" +#include "vdocument.h" + +void +VSelectNodes::visitVSubpath( VSubpath& path ) +{ + path.first(); + + VSegment *curr = path.current(); + + while( curr ) + { + if( m_rect.isEmpty() ) + { + for( int i = 0; i < curr->degree(); i++ ) + curr->selectPoint( i, m_select ); + + setSuccess(); + } + else + { + if( m_exclusive ) + { + // we are in exclusive mode, so deselect all nodes first + for( int i = 0; i < curr->degree(); i++ ) + curr->selectPoint( i, false ); + } + + if( curr->isCurve() ) + { + // select all control points inside the selection rect + for( int i = 0; i < curr->degree()-1; ++i ) + { + if( m_rect.contains( curr->point( i ) ) ) + { + curr->selectPoint( i, m_select ); + setSuccess(); + } + } + VSegment* prev = curr->prev(); + // make sure the last control point of the previous segment and the first control point + // of the current segment are selected if: + // - both segments are curves with a smooth transition and + // - the previous segment's knot is selected or + // - one of the above mentioned control points is already selected + if( prev ) + { + if( curr->pointIsSelected( 0 ) == m_select ) + { + if( prev->isCurve() && prev->isSmooth() ) + prev->selectPoint( prev->degree()-2, m_select ); + } + else + { + if( prev->knotIsSelected() || ( prev->isCurve() && prev->isSmooth() && prev->pointIsSelected( prev->degree()-2 ) ) ) + curr->selectPoint( 0, m_select ); + } + } + } + + if( m_rect.contains( curr->knot() ) ) + { + curr->selectKnot( m_select ); + // select the last control point before the knot, if segment is curve + if( curr->isCurve() && m_select ) + curr->selectPoint( curr->degree()-2 ); + + setSuccess(); + } + } + curr = curr->next(); + } + // select first node as well + if( path.isClosed() && path.getLast()->knotIsSelected() ) + path.getFirst()->selectKnot( m_select ); +} + +void +VSelectNodes::visitVLayer( VLayer& layer ) +{ + VDocument* doc = (VDocument*)layer.parent(); + if ( ( layer.state() != VObject::deleted ) && + ( ( doc->selectionMode() == VDocument::AllLayers ) || + ( doc->selectionMode() == VDocument::VisibleLayers && ( layer.state() == VObject::normal || layer.state() == VObject::normal_locked ) ) || + ( doc->selectionMode() == VDocument::SelectedLayers && layer.selected() ) || + ( doc->selectionMode() == VDocument::ActiveLayer && doc->activeLayer() == &layer ) ) ) + { + VObjectListIterator itr( layer.objects() ); + for( ; itr.current(); ++itr ) + itr.current()->accept( *this ); + } +} + +void +VTestNodes::visitVSubpath( VSubpath& path ) +{ + path.first(); + + while( path.current() ) + { + for( int i = 0; i < path.current()->degree(); i++ ) + if( m_rect.contains( path.current()->point( i ) ) ) //&& + //path.current()->pointIsSelected( i ) ) + { + m_segments.append( path.current() ); + setSuccess(); + // only add a segment once + break; + } + + path.next(); + } +} + +void +VTestNodes::visitVLayer( VLayer& layer ) +{ + VDocument* doc = (VDocument*)layer.parent(); + if ( ( layer.state() != VObject::deleted ) && + ( ( doc->selectionMode() == VDocument::AllLayers ) || + ( doc->selectionMode() == VDocument::VisibleLayers && ( layer.state() == VObject::normal || layer.state() == VObject::normal_locked ) ) || + ( doc->selectionMode() == VDocument::SelectedLayers && layer.selected() ) || + ( doc->selectionMode() == VDocument::ActiveLayer && doc->activeLayer() == &layer ) ) ) + { + VObjectListIterator itr( layer.objects() ); + for( ; itr.current(); ++itr ) + itr.current()->accept( *this ); + } +} + diff --git a/karbon/visitors/vselectnodes.h b/karbon/visitors/vselectnodes.h new file mode 100644 index 00000000..c4efc93c --- /dev/null +++ b/karbon/visitors/vselectnodes.h @@ -0,0 +1,71 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTNODES_H__ +#define __VSELECTNODES_H__ + + +#include "KoRect.h" + +#include "vvisitor.h" +#include "vsegment.h" + +class VSelectNodes : public VVisitor +{ +public: + VSelectNodes( bool select = true, bool exclusive = true ) + { + m_select = select; + m_exclusive = exclusive; + } + + VSelectNodes( const KoRect& rect, bool select = true, bool exclusive = true ) + { + m_select = select; + m_exclusive = exclusive; + m_rect = rect; + } + + virtual void visitVSubpath( VSubpath& path ); + virtual void visitVLayer( VLayer& layer ); + +private: + bool m_select; + bool m_exclusive; + KoRect m_rect; +}; + +class VTestNodes : public VVisitor +{ +public: + VTestNodes( const KoRect& rect ) : m_rect( rect ) { m_segments.clear(); } + + virtual void visitVSubpath( VSubpath& path ); + virtual void visitVLayer( VLayer& layer ); + + QPtrList<VSegment> &result() { return m_segments; } + +private: + KoRect m_rect; + QPtrList<VSegment> m_segments; +}; + +#endif + + diff --git a/karbon/visitors/vselectobjects.cc b/karbon/visitors/vselectobjects.cc new file mode 100644 index 00000000..060eeacb --- /dev/null +++ b/karbon/visitors/vselectobjects.cc @@ -0,0 +1,273 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vselectobjects.h" +#include "vlayer.h" +#include "vdocument.h" +#include "vsegment.h" +#include <kdebug.h> + +void +VSelectObjects::visitVPath( VPath& composite ) +{ + // Never select a deleted, locked or hidden object. + if( composite.state() > VObject::normal && + composite.state() < VObject::selected ) + return; + + if( m_rectMode && m_rect.isEmpty() ) // in this mode everything is selected + { + visitVObject( composite ); + return; + } + + bool selected = false; + + if( m_rectMode ) + { + // Check if composite is completely inside the selection rectangle. + // This test should be the first test since it's the less expensive one. + if( m_rect.contains( composite.boundingBox() ) ) + { + selected = true; + } + + // Check if any of the rectangle corners is inside the composite. + // This test should be done before the intersect test since it covers many + // intersection cases. + if( !selected ) + { + if( + composite.pointIsInside( m_rect.topLeft() ) || + composite.pointIsInside( m_rect.topRight() ) || + composite.pointIsInside( m_rect.bottomRight() ) || + composite.pointIsInside( m_rect.bottomLeft() ) ) + { + selected = true; + } + } + + // Check if selection rectangle intersects the composite. + if( !selected ) + { + // Path for holding a helper segment. + VSubpath path( 0L ); + + path.moveTo( m_rect.topLeft() ); + path.lineTo( m_rect.topRight() ); + + if( composite.intersects( *path.getLast() ) ) + { + selected = true; + } + else + { + path.getFirst()->setKnot( m_rect.bottomRight() ); + + if( composite.intersects( *path.getLast() ) ) + { + selected = true; + } + else + { + path.getLast()->setKnot( m_rect.bottomLeft() ); + + if( composite.intersects( *path.getLast() ) ) + { + selected = true; + } + else + { + path.getFirst()->setKnot( m_rect.topLeft() ); + + if( composite.intersects( *path.getLast() ) ) + { + selected = true; + } + } + } + } + } + } + else + { + if( composite.pointIsInside( m_point ) ) + selected = true; + } + + if( selected ) + { + if( m_select ) + { + composite.setState( VObject::selected ); + if( ! m_selection.containsRef( &composite ) ) + m_selection.append( &composite ); + } + else + { + composite.setState( VObject::normal ); + m_selection.remove( &composite ); + } + + setSuccess(); + } +} + +void +VSelectObjects::visitVObject( VObject& object ) +{ + // Never select a deleted, locked or hidden object. + if( object.state() > VObject::normal && + object.state() < VObject::selected ) + return; + + // selection by selection rectangle + if( m_rectMode ) + { + if( !m_rect.isEmpty() ) + { + if( m_select ) + { + if( m_rect.intersects( object.boundingBox() ) ) + { + object.setState( VObject::selected ); + if( ! m_selection.containsRef( &object ) ) + m_selection.append( &object ); + setSuccess(); + } + } + else + { + if( m_rect.intersects( object.boundingBox() ) ) + { + object.setState( VObject::normal ); + m_selection.remove( &object ); + setSuccess(); + } + } + } + else + { + if( m_select ) + { + object.setState( VObject::selected ); + if( ! m_selection.containsRef( &object ) ) + m_selection.append( &object ); + setSuccess(); + } + else + { + object.setState( VObject::normal ); + m_selection.remove( &object ); + setSuccess(); + } + } + } + // selection by point + else + { + if( object.boundingBox().contains( m_point ) ) + { + if( m_select ) + { + object.setState( VObject::selected ); + if( ! m_selection.containsRef( &object ) ) + m_selection.append( &object ); + } + else + { + object.setState( VObject::normal ); + m_selection.remove( &object ); + } + setSuccess(); + } + } + +} + +void +VSelectObjects::visitVLayer( VLayer& layer ) +{ + VDocument* doc = (VDocument*)layer.parent(); + if ( ( layer.state() != VObject::deleted ) && + ( ( doc->selectionMode() == VDocument::AllLayers ) || + ( doc->selectionMode() == VDocument::VisibleLayers && ( layer.state() == VObject::normal || layer.state() == VObject::normal_locked ) ) || + ( doc->selectionMode() == VDocument::SelectedLayers && layer.selected() ) || + ( doc->selectionMode() == VDocument::ActiveLayer && doc->activeLayer() == &layer ) ) ) + { + VObjectListIterator itr( layer.objects() ); + for( ; itr.current(); ++itr ) + itr.current()->accept( *this ); + } +} + +void +VSelectObjects::visitVText( VText& text ) +{ + // Never select a deleted, locked or hidden object. + if( text.state() > VObject::normal && + text.state() < VObject::selected ) + return; + + int deselectedGlyphs = 0; + + VPathListIterator itr( text.glyphs() ); + for( ; itr.current(); ++itr ) + { + VPath c( 0L ); + c.combine( *itr.current() ); + visitVPath( c ); + if( m_select && c.state() == VObject::selected ) + { + kdDebug(38000) << "selected: " << itr.current() << endl; + m_selection.remove( &c ); + text.setState( VObject::selected ); + if( ! m_selection.containsRef( &text ) ) + m_selection.append( &text ); + return; + } + else if( c.state() == VObject::normal ) + { + kdDebug(38000) << "deselected: " << itr.current() << endl; + deselectedGlyphs++; + } + } + if( deselectedGlyphs >= 0 && uint( deselectedGlyphs ) == text.glyphs().count() ) + { + text.setState( VObject::normal ); + m_selection.remove( &text ); + } +} + +void +VSelectObjects::visitVGroup( VGroup& group ) +{ + // Never select a deleted, locked or hidden object. + if( group.state() > VObject::normal && + group.state() < VObject::selected ) + return; + + if( ! m_insideGroups ) + visitVObject( group ); + else + { + VVisitor::visitVGroup( group ); + } +} diff --git a/karbon/visitors/vselectobjects.h b/karbon/visitors/vselectobjects.h new file mode 100644 index 00000000..f42e0ad5 --- /dev/null +++ b/karbon/visitors/vselectobjects.h @@ -0,0 +1,71 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSELECTOBJECTS_H__ +#define __VSELECTOBJECTS_H__ + + +#include "KoRect.h" + +#include "vcomposite.h" +#include "vgroup.h" +#include "vtext.h" +#include "vimage.h" +#include "vvisitor.h" + +/** + * This visitor visits a selection and selects objects that are contained + * in a paramater selection rectangle. For composites it makes a more accurate test, if the + * selection rectangle intersects with any part of the composite, it is selected. + * Also this visitor can be used to deselect objects. + */ +class VSelectObjects : public VVisitor +{ +public: + VSelectObjects( VObjectList& selection, bool select = true ) + : m_selection( selection ), m_select( select ), m_rectMode( true ), m_insideGroups( false ) {} + + VSelectObjects( VObjectList& selection, const KoRect& rect, bool select = true ) + : m_selection( selection ), m_select( select ), m_rect( rect ), m_rectMode( true ), m_insideGroups( false ) { } + + VSelectObjects( VObjectList& selection, const KoPoint& point, bool select = true, bool insideGroups = false ) + : m_selection( selection ), m_select( select ), m_point( point ), m_rectMode( false ), m_insideGroups( insideGroups ) {} + + virtual void visitVGroup( VGroup& group ); + virtual void visitVPath( VPath& composite ); + virtual void visitVText( VText& text ); + virtual void visitVImage( VImage& img ) + { visitVObject( img ); } + virtual void visitVLayer( VLayer& layer ); + +private: + void visitVObject( VObject& object ); + + VObjectList& m_selection; + + bool m_select; + + KoRect m_rect; + KoPoint m_point; + bool m_rectMode; + bool m_insideGroups; +}; + +#endif + diff --git a/karbon/visitors/vtransformnodes.cc b/karbon/visitors/vtransformnodes.cc new file mode 100644 index 00000000..ed670538 --- /dev/null +++ b/karbon/visitors/vtransformnodes.cc @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + + +#include "vpath.h" +#include "vsegment.h" +#include "vtransformnodes.h" + + +VTransformNodes::VTransformNodes( const QWMatrix& m ) + : m_matrix( m ) +{ +} + +void +VTransformNodes::visitVSubpath( VSubpath& path ) +{ + path.first(); + while( path.current() ) + { + if( path.current()->isCurve() ) + { + if( !path.current()->knotIsSelected() && + path.current()->pointIsSelected( 1 ) && + path.current()->next() && + path.current()->next()->isCurve() && + !path.current()->next()->pointIsSelected( 0 ) && + path.current()->isSmooth() ) + { + // Do extra reverse trafo for smooth beziers + QWMatrix m2( m_matrix.m11(), m_matrix.m12(), m_matrix.m21(), m_matrix.m22(), + -m_matrix.dx(), -m_matrix.dy() ); + path.current()->next()->setPoint( 0, path.current()->next()->point( 0 ).transform( m2 ) ); + } + if( path.current()->pointIsSelected( 0 ) && + path.current()->prev() && + path.current()->prev()->isCurve() && + !path.current()->prev()->knotIsSelected() && + !path.current()->prev()->pointIsSelected( 1 ) && + path.current()->prev()->isSmooth() ) + { + // Do extra reverse trafo for smooth beziers + QWMatrix m2( m_matrix.m11(), m_matrix.m12(), m_matrix.m21(), m_matrix.m22(), + -m_matrix.dx(), -m_matrix.dy() ); + path.current()->prev()->setPoint( 1, path.current()->prev()->point( 1 ).transform( m2 ) ); + } + } + + for( uint i = 0; i < path.current()->degree(); ++i ) + { + if( path.current()->pointIsSelected( i ) ) + path.current()->setPoint( i, path.current()->point( i ).transform( m_matrix ) ); + } + + if( !success() ) + setSuccess(); + path.next(); + } +} + diff --git a/karbon/visitors/vtransformnodes.h b/karbon/visitors/vtransformnodes.h new file mode 100644 index 00000000..5c384e61 --- /dev/null +++ b/karbon/visitors/vtransformnodes.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTRANSFORMNODES_H__ +#define __VTRANSFORMNODES_H__ + +#include <qwmatrix.h> +#include <koffice_export.h> +#include "vvisitor.h" + + +class VSegment; + + +class KARBONBASE_EXPORT VTransformNodes : public VVisitor +{ +public: + VTransformNodes( const QWMatrix& m ); + + virtual void visitVSubpath( VSubpath& path ); + +private: + QWMatrix m_matrix; +}; + +#endif + diff --git a/karbon/vtool.cc b/karbon/vtool.cc new file mode 100644 index 00000000..66114048 --- /dev/null +++ b/karbon/vtool.cc @@ -0,0 +1,279 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qevent.h> +#include <qlabel.h> + +#include <kdebug.h> +#include <kiconloader.h> + +#include "karbon_view.h" +#include "karbon_part.h" +#include "vtoolcontroller.h" +#include "KoContextCelp.h" +#include "vtool.h" +#include "vtool.moc" + + +VTool::VTool( KarbonView *view, const char *name ) : QObject( 0, name ), m_view( view ) +{ + m_mouseButtonIsDown = false; + m_isDragging = false; + m_shiftPressed = false; + m_ctrlPressed = false; + m_altPressed = false; + m_action = 0; +} + +VTool::~VTool() +{ + if (toolController()) + toolController()->unregisterTool( this ); + + delete m_action; + //kdDebug(38000) << "Deleting : " << name().latin1() << endl; +} + +void +VTool::registerTool( VTool *tool ) +{ + toolController()->registerTool( tool ); +} + +VToolController * +VTool::toolController() const +{ + return m_view->toolController(); +} + +KarbonView * +VTool::view() const +{ + return m_view; +} + +bool +VTool::mouseEvent( QMouseEvent* mouseEvent, const KoPoint &canvasCoordinate ) +{ + if( !view() || !view()->part() || !view()->part()->isReadWrite() ) + return false; + + m_lastPoint.setX( canvasCoordinate.x() ); + m_lastPoint.setY( canvasCoordinate.y() ); + + setCursor(); + + m_altPressed = mouseEvent->state() & Qt::AltButton; + m_shiftPressed = mouseEvent->state() & Qt::ShiftButton; + m_ctrlPressed = mouseEvent->state() & Qt::ControlButton; + + // Mouse events: + if( mouseEvent->type() == QEvent::MouseButtonDblClick ) + { + mouseButtonDblClick(); + + return true; + } + + if( mouseEvent->type() == QEvent::MouseButtonPress ) + { + m_firstPoint.setX( canvasCoordinate.x() ); + m_firstPoint.setY( canvasCoordinate.y() ); + + if( mouseEvent->button() == QEvent::RightButton ) + rightMouseButtonPress(); + else + mouseButtonPress(); + + m_mouseButtonIsDown = true; + + return true; + } + + if( mouseEvent->type() == QEvent::MouseMove ) + { + //setCursor(); + + if( m_mouseButtonIsDown ) + { + mouseDrag(); + + m_isDragging = true; + } + else + mouseMove(); + + return true; + } + + if( mouseEvent->type() == QEvent::MouseButtonRelease ) + { + if( m_isDragging ) + { + mouseDragRelease(); + + m_isDragging = false; + } + else if( m_mouseButtonIsDown ) // False if canceled. + if( mouseEvent->button() == QEvent::RightButton ) + rightMouseButtonRelease(); + else + mouseButtonRelease(); + + m_mouseButtonIsDown = false; + + return true; + } + + return false; +} + +bool +VTool::keyEvent( QEvent* event ) +{ + // Key press events. + if( event->type() == QEvent::KeyPress ) + { + QKeyEvent* keyEvent = static_cast<QKeyEvent*>( event ); + + // Terminate the current drawing with the Enter-key: + if( + ( keyEvent->key() == Qt::Key_Enter || + keyEvent->key() == Qt::Key_Return ) + && !m_isDragging ) + { + accept(); + + return true; + } + + // Terminate the current drawing with the Enter-key: + if( keyEvent->key() == Qt::Key_Backspace && !m_isDragging ) + { + cancelStep(); + + return true; + } + + // Cancel dragging with ESC-key: + if( keyEvent->key() == Qt::Key_Escape ) + { + cancel(); + + m_isDragging = false; + m_mouseButtonIsDown = false; + + return true; + } + + // If SHIFT is pressed, some tools create a "square" object while dragging: + if( keyEvent->key() == Qt::Key_Shift ) + { + m_shiftPressed = true; + if( m_isDragging ) + { + mouseDragShiftPressed(); + + return true; + } + } + + // If Ctrl is pressed, some tools create a "centered" object while dragging: + if( keyEvent->key() == Qt::Key_Control ) + { + m_ctrlPressed = true; + if( m_isDragging ) + { + mouseDragCtrlPressed(); + + return true; + } + } + + } + + // Key release events: + if( event->type() == QEvent::KeyRelease ) + { + QKeyEvent* keyEvent = static_cast<QKeyEvent*>( event ); + + Qt::Key key = (Qt::Key)keyEvent->key(); + if( key == Qt::Key_Shift ) + { + m_shiftPressed = false; + if( m_isDragging ) + { + mouseDragShiftReleased(); + + return true; + } + } + + if( key == Qt::Key_Control ) + { + m_ctrlPressed = false; + if( m_isDragging ) + { + mouseDragCtrlReleased(); + + return true; + } + } + + if( key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down ) + { + arrowKeyReleased( key ); + return true; + } + + return keyReleased( key ); + } + + return false; +} + +void +VTool::activate() +{ + kdDebug() << k_funcinfo << endl; + refreshUnit(); + QPixmap Icon = BarIcon( icon() ); + view()->contextHelpAction()->updateHelp( uiname(), contextHelp(), &Icon ); + view()->statusMessage()->setText( statusText() ); + toolController()->setCurrentTool( this ); +#if 0 + if( toolController()->activeTool() ) + { + toolController()->activeTool()->action()->setChecked( false ); + toolController()->activeTool()->deactivate(); + } + + if( toolController()->activeTool() == this ) + showDialog(); + else + { + refreshUnit(); + QPixmap Icon = BarIcon( icon() ); + view()->contextHelpAction()->updateHelp( uiname(), contextHelp(), &Icon ); + view()->statusMessage()->setText( statusText() ); + toolController()->activeTool()->action()->setChecked( true ); + } +#endif +} + diff --git a/karbon/vtool.h b/karbon/vtool.h new file mode 100644 index 00000000..6447225f --- /dev/null +++ b/karbon/vtool.h @@ -0,0 +1,355 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTOOL_H__ +#define __VTOOL_H__ + +#include <qobject.h> +#include <kaction.h> +#include <klocale.h> +#include <KoPoint.h> +#include <koffice_export.h> +class KRadioAction; +class KarbonPart; +class KarbonView; +class QEvent; +class QWidget; +class VPainter; +class VToolController; + +enum enumToolType +{ + TOOL_SELECT = 0, // + TOOL_FREEHAND = 1, // + TOOL_SHAPE = 2, // Geometric shapes like ellipses and lines + TOOL_MANIPULATION = 3, // + TOOL_MISC = 4 // +}; + +/** + * The base class for all karbon tools. + * + * Each tool has an icon, name and category. Basic mouse event and key handling is + * implemented here. + */ +class KARBONBASE_EXPORT VTool : public QObject +{ + Q_OBJECT + +public: + /** + * Constructs a new tool connected to the specified karbon view. + * + * @param view the karbon view the tool is connected to + * @param name unused + */ + VTool( KarbonView *view, const char* name ); + // Make VTool "abstract": + + /** + * Destroys the tool and unregisters it from the connected part. + */ + virtual ~VTool(); + + /** + * Registers the specified tool at the connected part. + * + * Tools should register themselves by calling this function. + * + * @param tool the tool to register + */ + virtual void registerTool( VTool *tool ); + + /** + * Deactivates the tool. + */ + virtual void deactivate() {} + + /** + * Shows the tools option dialog. + */ + virtual bool showDialog() const { return false; } + + /** + * The name of the tool. + */ + virtual QString uiname() { return i18n( "Unnamed Tool" ); } + + /** + * The context help of the tool. + */ + virtual QString contextHelp() { return i18n( "This tool has no description." ); } + + /** + * The tool type. + */ + virtual enumToolType toolType() { return TOOL_MISC; } + + /** + * The tool status text. + */ + virtual QString statusText() { return ""; } + + /** + * Position in toolbox. Zero means no preferred position, other + * values indicate the true position. + */ + virtual uint priority() { return 0; } + + /** + * The tool icon name. + */ + QString icon() { return m_action->icon(); } + + /** + * This function processes every important mouse event. + * It then calls suiting functions like mouseMoved() so deriving tools + * don't need to directly deal with events themselves. + */ + bool mouseEvent( QMouseEvent* event, const KoPoint& ); + + /** + * This function processes every important key event. + * It then calls suiting functions like mouseButtonPress() so deriving tools + * don't need to directly deal with events themselves. + */ + bool keyEvent( QEvent* event ); + + /** + * This function is called when the documents unit setting were changed. + */ + virtual void refreshUnit() {} + + /** + * Called after tool creation. A tool is supposed to hook its associated action + * into the specified action collection here. + */ + virtual void setup(KActionCollection *) {} + + /** + * Returns the tool's associated action object. + * + * @return the associated action + */ + KRadioAction *action() const { return m_action; } + + /** + * Draws the actual tool state. + * + * @param painter the painter on which to paint + */ + virtual void draw( VPainter* painter ) { Q_UNUSED( painter ); } + +public slots: + /** + * Called during the tool activation. A tool is supposed to set a mouse cursor and/or + * the statusbar properly here. + */ + virtual void activate(); + +protected: + /** + * Returns the current dagging state. + * + * @return true if the mouse is currently dragged, else false + */ + bool isDragging() const { return m_isDragging; } + + virtual void draw( /*VPainter* painter*/ ) {} + + /** + * This function is called on each mouse event the tool receives. + */ + virtual void setCursor() const {} + + /** + * Left mouse button press. + */ + virtual void mouseButtonPress() {} + + /** + * Right mouse button press. + */ + virtual void rightMouseButtonPress() {} + + /** + * Left mouse button release. The mouse wasn't moved. + */ + virtual void mouseButtonRelease() {} + + /** + * Right mouse button release. The mouse wasn't moved. + */ + virtual void rightMouseButtonRelease() {} + + /** + * Mouse button double click. + */ + virtual void mouseButtonDblClick() {} + + /** + * Mouse move. No mouse button is pressed. + */ + virtual void mouseMove() {} + + /** + * Mouse drag. + */ + virtual void mouseDrag() {} + + /** + * Mouse button release. The mouse was moved before. + */ + virtual void mouseDragRelease() {} + + /** + * Mouse drag with "Shift" key pressed at the same time. + */ + virtual void mouseDragShiftPressed() {} + + /** + * Mouse drag with "Ctrl" key pressed at the same time. + */ + virtual void mouseDragCtrlPressed() {} + + /** + * "Shift" key released while mouse drag. + */ + virtual void mouseDragShiftReleased() {} + + /** + * "Ctrl" key released while mouse drag. + */ + virtual void mouseDragCtrlReleased() {} + + /** + * "Arrow" key released up, down, left, right + */ + virtual void arrowKeyReleased( Qt::Key ) {} + + /** + * Specified key released. + */ + virtual bool keyReleased( Qt::Key ) { return false; } + + /** + * Cancels all tool operations. This event is invoked when ESC is pressed. + */ + virtual void cancel() {} + + /** + * Cancels the last tool step (if any). This event is invoked when Backspace is pressed. + */ + virtual void cancelStep() {} + + /** + * Terminates the current tool drawing (if any). This event is invoked when Enter/Return is pressed. + */ + virtual void accept() {} + + /** + * Returns the connected karbon part. + */ +// KarbonPart* part() const { return m_part; } + + /** + * Returns the connected karbon view. + */ + KarbonView* view() const; + + /** + * Most tools need to know the first mouse coordinate. + */ + const KoPoint& first() const { return m_firstPoint; } + + /** + * The last mouse coordinate. + */ + const KoPoint& last() const { return m_lastPoint; } + + /** + * The status of the shift key. + * + * @return true if key is pressed, else false + */ + bool shiftPressed() const { return m_shiftPressed; } + + /** + * The status of the ctrl key. + * + * @return true if key is pressed, else false + */ + bool ctrlPressed() const { return m_ctrlPressed; } + + /** + * The status of the alt key. + * + * @return true if key is pressed, else false + */ + bool altPressed() const { return m_altPressed; } + + /** The tool's action object. */ + KRadioAction *m_action; + + /** Helper function. Returns the parent view's toolcontroller. */ + VToolController *toolController() const; + +private: + /** + */ + KarbonView *m_view; + + /** + * First input mouse coordinate. + */ + KoPoint m_firstPoint; + + /** + * Last input mouse coordinate. + */ + KoPoint m_lastPoint; + + /** + * A tool state. + */ + bool m_mouseButtonIsDown; + + /** + * A tool state. + */ + bool m_isDragging; + + /** + * Indicates if shift is pressed. + */ + bool m_shiftPressed; + + /** + * Indicates if ctrl is pressed. + */ + bool m_ctrlPressed; + + /** + * Indicates if Alt is pressed. + */ + bool m_altPressed; +}; + +#endif + diff --git a/karbon/vtoolcontroller.cc b/karbon/vtoolcontroller.cc new file mode 100644 index 00000000..4ce02c79 --- /dev/null +++ b/karbon/vtoolcontroller.cc @@ -0,0 +1,167 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "karbon_tool_registry.h" +#include "karbon_part.h" +#include <vselection.h> +#include "vtoolcontroller.h" +#include "vtool.h" +#include "vtoolbox.h" + +VToolController::VToolController( KarbonView *view ) : m_view( view ), m_currentTool( 0L ), m_setup( false ) +{ + m_tools.setAutoDelete( true ); +} + +void +VToolController::init() +{ +} + +VToolController::~VToolController() +{ +} + +void +VToolController::setCurrentTool( VTool *tool ) +{ + if( m_currentTool ) + { + m_currentTool->action()->setChecked( false ); + m_currentTool->deactivate(); + } + + if( m_currentTool && m_currentTool == tool ) + m_currentTool->showDialog(); + else + { + m_currentTool = tool; + + if( ! tool ) + return; + + m_currentTool->action()->setChecked( true ); + m_currentTool->action()->activate(); + } + m_toolBox->slotSetTool( tool->name() ); +} + +void +VToolController::registerTool( VTool *tool ) +{ + if( !m_tools.find( tool->name() ) ) + m_tools.insert( tool->name(), tool ); + //kdDebug(38000) << "active tool : " << m_currentTool->name() << endl; +} + +void +VToolController::unregisterTool( VTool *tool ) +{ + // tool->name() is not valid in VTool destructor + QDictIterator<VTool> it( m_tools ); + for( ; it.current(); ++it ) + if (it.current() == tool) + { + m_tools.remove(it.currentKey()); + return; + } +} + +bool +VToolController::mouseEvent( QMouseEvent* event, const KoPoint &p ) +{ + if( !m_currentTool ) { + return false; + } + + return m_currentTool->mouseEvent( event, p ); +} + +bool +VToolController::keyEvent( QEvent* event ) +{ + if( !m_currentTool ) { + return false; + } + + return m_currentTool->keyEvent( event ); +} + +void +VToolController::setUp( KActionCollection *ac, VToolBox * toolbox ) +{ + if( m_setup ) + { + resetToolBox( toolbox); + return; + } + + KarbonToolRegistry::instance()->createTools( ac, m_view ); + + m_toolBox = toolbox; + + QDictIterator<VTool> it( m_tools ); + for( ; it.current(); ++it ) + toolbox->registerTool( it.current() ); + + toolbox->setupTools(); + + VTool *t = findTool( "tool_select" ); + setCurrentTool(t); + + m_setup = true; +} + +void +VToolController::resetToolBox( VToolBox * toolbox ) +{ + m_toolBox = toolbox; + + QDictIterator<VTool> it( m_tools ); + for( ; it.current(); ++it ) + toolbox->registerTool( it.current() ); + + toolbox->setupTools(); + + if( m_currentTool ) + { + // restore the old current tool + setCurrentTool( m_currentTool ); + m_currentTool = 0; + } +} + +VTool * +VToolController::findTool( const QString &toolName ) const +{ + VTool *tool = 0; + QDictIterator<VTool> it( m_tools ); + for( ; it.current(); ++it ) + if( it.current()->name() == toolName ) + return it.current(); + return tool; +} + +void +VToolController::youAintGotNoToolBox() +{ + m_toolBox = 0; + //m_currentTool = currentTool(); +} + diff --git a/karbon/vtoolcontroller.h b/karbon/vtoolcontroller.h new file mode 100644 index 00000000..69df1219 --- /dev/null +++ b/karbon/vtoolcontroller.h @@ -0,0 +1,67 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTOOLCONTROLLER_H__ +#define __VTOOLCONTROLLER_H__ + +#include <qdict.h> +#include <KoPoint.h> + +class QEvent; + +class VTool; +class KarbonView; +class VToolBox; + +class VToolController +{ +public: + VToolController( KarbonView *view ); + virtual ~VToolController(); + + void init(); + + void registerTool( VTool *tool ); + void unregisterTool( VTool *tool ); + + void setCurrentTool( VTool * ); + VTool *currentTool() const { return m_currentTool; } + + bool mouseEvent( QMouseEvent* event, const KoPoint& ); + bool keyEvent( QEvent* event ); + + const QDict<VTool> &tools() { return m_tools; } + + void setUp( KActionCollection *ac, VToolBox * toolbox ); + void resetToolBox( VToolBox * toolbox ); + VTool *findTool( const QString &toolName ) const; + + // Called when the toolbox is deleted because the view was made inactive in favour of another view + void youAintGotNoToolBox(); + +private: + KarbonView *m_view; + VTool *m_currentTool; + QDict<VTool> m_tools; + VToolBox *m_toolBox; + bool m_setup; +}; + +#endif + diff --git a/karbon/widgets/Makefile.am b/karbon/widgets/Makefile.am new file mode 100644 index 00000000..c78d166c --- /dev/null +++ b/karbon/widgets/Makefile.am @@ -0,0 +1,53 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../core \ + -I$(srcdir)/../commands \ + -I$(srcdir)/../render \ + -I$(srcdir)/../dialogs \ + -I$(srcdir)/../dockers \ + -I$(srcdir)/../tools \ + $(all_includes) + +noinst_LTLIBRARIES = \ + libkarbonwidgets.la + +noinst_HEADERS = \ + vcanvas.h \ + vcolorslider.h \ + vgradientwidget.h \ + vgradienttabwidget.h \ + vreference.h \ + vstrokefillpreview.h \ + vtranslate.h \ + vselecttoolbar.h \ + vsmallpreview.h \ + vstatebutton.h \ + vtoolbox.h \ + vtypebuttonbox.h \ + vruler.h + +libkarbonwidgets_la_SOURCES = \ + dummy.cc \ + vcanvas.cc \ + vcolorslider.cc \ + vgradientwidget.cc \ + vgradienttabwidget.cc \ + vreference.cc \ + vstrokefillpreview.cc \ + vtranslate.cc \ + vselecttoolbar.cc \ + vsmallpreview.cc \ + vstatebutton.cc \ + vtoolbox.cc \ + vtypebuttonbox.cc \ + vruler.cc + +libkarbonwidgets_la_METASOURCES = \ + AUTO + +DISTCLEANFILES = \ + dummy.cc + +dummy.cc: + echo > dummy.cc + diff --git a/karbon/widgets/vcanvas.cc b/karbon/widgets/vcanvas.cc new file mode 100644 index 00000000..c3c91670 --- /dev/null +++ b/karbon/widgets/vcanvas.cc @@ -0,0 +1,380 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcursor.h> +#include <qpainter.h> +#include <qpixmap.h> + +#include "karbon_view.h" +#include "karbon_part.h" +#include "karbon_drag.h" +#include "vcanvas.h" +#include "vdocument.h" +#include "vpainter.h" +#include "vqpainter.h" +#include "vpainterfactory.h" +#include "vselection.h" +#include "vtoolcontroller.h" +#include "vtool.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kcolordrag.h> + +int +VCanvas::pageOffsetX() const +{ + double zoomedWidth = m_part->document().width() * m_view->zoom(); + if( contentsWidth() < visibleWidth() ) + return int( 0.5 * ( visibleWidth() - zoomedWidth ) ); + else + return int( 0.5 * ( contentsWidth() - zoomedWidth ) ); +} + +int +VCanvas::pageOffsetY() const +{ + double zoomedHeight = m_part->document().height() * m_view->zoom(); + if( contentsHeight() < visibleHeight() ) + return int( 0.5 * ( visibleHeight() - zoomedHeight ) ); + else + return int( 0.5 * ( contentsHeight() - zoomedHeight ) ); +} + +KoPoint VCanvas::snapToGrid( const KoPoint &point ) +{ + if( !m_part->document().grid().isSnap ) + return point; + + KoPoint p = point; + + KoSize dist = m_part->document().grid().snap; + KoSize dxy = m_part->document().grid().freq; + + int dx = qRound( p.x() / dxy.width() ); + int dy = qRound( p.y() / dxy.height() ); + + float distx = QMIN( QABS( p.x() - dxy.width() * dx ), QABS( p.x() - dxy.width() * ( dx + 1 ) ) ); + float disty = QMIN( QABS( p.y() - dxy.height() * dy ), QABS( p.y() - dxy.height() * ( dy + 1 ) ) ); + + if( distx < dist.width() ) + { + if( QABS(p.x() - dxy.width() * dx ) < QABS( p.x() - dxy.width() * ( dx + 1 ) ) ) + p.rx() = dxy.width() * dx; + else + p.rx() = dxy.width() * ( dx + 1 ); + } + + if( disty < dist.height() ) + { + if( QABS( p.y() - dxy.height() * dy ) < QABS( p.y() - dxy.height() * ( dy + 1 ) ) ) + p.ry() = dxy.height() * dy; + else + p.ry() = dxy.height() * ( dy + 1 ); + } + + return p; +} + + +VCanvas::VCanvas( QWidget *parent, KarbonView* view, KarbonPart* part ) + : QScrollView( parent, "canvas", WStaticContents/*WNorthWestGravity*/ | WResizeNoErase | + WRepaintNoErase ), m_part( part ), m_view( view ) +{ + connect(this, SIGNAL( contentsMoving( int, int ) ), this, SLOT( slotContentsMoving( int, int ) ) ); + viewport()->setFocusPolicy( QWidget::StrongFocus ); + + viewport()->setMouseTracking( true ); + setMouseTracking( true ); + + viewport()->setBackgroundColor( Qt::white ); + viewport()->setBackgroundMode( QWidget::NoBackground ); + viewport()->installEventFilter( this ); + + resizeContents( 800, 600 ); + m_pixmap = new QPixmap( 800, 600 ); + + setFocus(); + + setAcceptDrops( true ); +} + +VCanvas::~VCanvas() +{ + delete m_pixmap; + m_view = 0L; + m_part = 0L; +} + +void +VCanvas::setPos( const KoPoint& p ) +{ + KoPoint p2 = toViewport( p ); + QCursor::setPos( mapToGlobal( QPoint( int(p2.x()), int(p2.y()) ) ) ); +} + +bool +VCanvas::eventFilter( QObject* object, QEvent* event ) +{ + QScrollView::eventFilter( object, event ); + + if( event->type() == QEvent::AccelOverride || event->type() == QEvent::Accel ) + return QScrollView::eventFilter( object, event ); + + if( event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease ) + return m_view->keyEvent( event ); + + QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>( event ); + + if( mouseEvent && m_view ) + { + KoPoint canvasCoordinate = toContents( KoPoint( mouseEvent->pos() ) ); + return m_view->mouseEvent( mouseEvent, canvasCoordinate ); + } + + return false; +} + + +// This causes a repaint normally, so just overwriting it omits the repainting +void +VCanvas::focusInEvent( QFocusEvent * ) +{ +} + +KoPoint +VCanvas::toViewport( const KoPoint &p ) const +{ + KoPoint p2 = p; + p2.setX( ( p.x() * m_view->zoom() ) - contentsX() + pageOffsetX() ); + if( contentsHeight() > height() ) + p2.setY( ( contentsHeight() - ( p.y() * m_view->zoom() + contentsY() + pageOffsetY() ) ) ); + else + p2.setY( ( height() - p.y() * m_view->zoom() + pageOffsetY() ) ); + return p2; +} + +KoPoint +VCanvas::toContents( const KoPoint &p ) const +{ + KoPoint p2 = p; + p2.setX( ( p.x() + contentsX() - pageOffsetX() ) / m_view->zoom() ); + if( contentsHeight() > height() ) + p2.setY( ( contentsHeight() - ( p.y() + contentsY() + pageOffsetY()) ) / m_view->zoom() ); + else + p2.setY( ( height() - p.y() - pageOffsetY() ) / m_view->zoom() ); + return p2; +} + +KoRect +VCanvas::boundingBox() const +{ + KoPoint p1( 0, 0 ); + KoPoint p2( width(), height() ); + if( !m_view->documentDeleted() ) + { + p1 = toContents( p1 ); + p2 = toContents( p2 ); + } + return KoRect( p1, p2 ).normalize(); +} + +void +VCanvas::setYMirroring( VPainter *p ) +{ + QWMatrix mat; + + mat.scale( 1, -1 ); + mat.translate( pageOffsetX(), pageOffsetY() ); + + if( contentsHeight() > visibleHeight() ) + mat.translate( -contentsX(), contentsY() - contentsHeight() ); + else + mat.translate( 0, -visibleHeight() ); + + p->setWorldMatrix( mat ); +} + +void +VCanvas::viewportPaintEvent( QPaintEvent *e ) +{ + QRect eventRect = e->rect(); + KoRect rect = KoRect::fromQRect( eventRect ); + + setYMirroring( m_view->painterFactory()->editpainter() ); + viewport()->setUpdatesEnabled( false ); + VPainter *p = m_view->painterFactory()->painter(); + + // TODO : only update ROIs + p->begin(); + p->clear( rect, QColor( 195, 194, 193 ) ); + p->setZoomFactor( m_view->zoom() ); + setYMirroring( p ); + + // TRICK : slightly adjust the matrix so libart AA looks better + QWMatrix mat = p->worldMatrix(); + p->setWorldMatrix( mat.translate( -.5, -.5 ) ); + + // set up clippath + p->newPath(); + p->moveTo( rect.topLeft() ); + p->lineTo( rect.topRight() ); + p->lineTo( rect.bottomRight() ); + p->lineTo( rect.bottomLeft() ); + p->lineTo( rect.topLeft() ); + p->setClipPath(); + + m_part->document().drawPage( p, m_part->pageLayout(), m_view->showPageMargins() ); + KoRect bbox = boundingBox(); + m_part->document().draw( p, &bbox ); + + p->resetClipPath(); + p->end(); + + // draw handle: + VQPainter qpainter( p->device() ); + setYMirroring( &qpainter ); + qpainter.setZoomFactor( m_view->zoom() ); + m_part->document().selection()->draw( &qpainter, m_view->zoom() ); + + if( m_view->toolController()->currentTool() ) + m_view->toolController()->currentTool()->draw( &qpainter ); + + bitBlt( viewport(), eventRect.topLeft(), p->device(), eventRect ); + viewport()->setUpdatesEnabled( true ); +} + +void +VCanvas::setViewport( double centerX, double centerY ) +{ + setContentsPos( int( centerX * contentsWidth() - 0.5 * visibleWidth() ), + int( centerY * contentsHeight() - 0.5 * visibleHeight() ) ); +} + +void +VCanvas::setViewportRect( const KoRect &r ) +{ + viewport()->setUpdatesEnabled( false ); + double zoomX = m_view->zoom() * ( ( visibleWidth() / m_view->zoom() ) / r.width() ); + double zoomY = m_view->zoom() * ( ( visibleHeight() / m_view->zoom() ) / r.height() ); + double pageOffX = ( contentsWidth() - ( m_part->document().width() * m_view->zoom() ) ) / 2.0; + double centerX = double( ( r.center().x() ) * m_view->zoom() + pageOffX ) / double( contentsWidth() ); + double pageOffY = ( contentsHeight() - ( m_part->document().height() * m_view->zoom() ) ) / 2.0; + double centerY = double( ( r.center().y() ) * m_view->zoom() + pageOffY ) / double( contentsHeight() ); + double zoom = zoomX < zoomY ? zoomX : zoomY; + resizeContents( int( ( zoom / m_view->zoom() ) * contentsWidth() ), + int( ( zoom / m_view->zoom() ) * contentsHeight() ) ); + setViewport( centerX, 1.0 - centerY ); + m_view->setZoomAt( zoom ); + viewport()->setUpdatesEnabled( true ); +} + +void +VCanvas::drawContents( QPainter* painter, int clipx, int clipy, + int clipw, int cliph ) +{ + drawDocument( painter, KoRect( clipx, clipy, clipw, cliph ) ); +} + +void +VCanvas::drawDocument( QPainter* /*painter*/, const KoRect&, bool drawVObjects ) +{ + setYMirroring( m_view->painterFactory()->editpainter() ); + + VPainter* p = m_view->painterFactory()->painter(); + if( drawVObjects ) + { + p->begin(); + p->clear( QColor( 195, 194, 193 ) ); + p->setZoomFactor( m_view->zoom() ); + setYMirroring( p ); + // TRICK : slightly adjust the matrix so libart AA looks better + QWMatrix mat = p->worldMatrix(); + p->setWorldMatrix( mat.translate( -.5, -.5 ) ); + + m_part->document().drawPage( p, m_part->pageLayout(), m_view->showPageMargins() ); + KoRect r2 = boundingBox(); + m_part->document().draw( p, &r2 ); + + p->end(); + } + + // draw handle: + VQPainter qpainter( p->device() ); + setYMirroring( &qpainter ); + qpainter.setZoomFactor( m_view->zoom() ); + m_part->document().selection()->draw( &qpainter, m_view->zoom() ); + + if( m_view->toolController()->currentTool() ) + m_view->toolController()->currentTool()->draw( &qpainter ); + + bitBlt( viewport(), 0, 0, p->device(), 0, 0, width(), height() ); +} + +void +VCanvas::repaintAll( bool drawVObjects ) +{ + drawDocument( 0, KoRect( 0, 0, width(), height() ), drawVObjects ); +} + +/// repaints just a rect area (no scrolling) +void +VCanvas::repaintAll( const KoRect &r ) +{ + drawDocument( 0, r ); +} + +void +VCanvas::resizeEvent( QResizeEvent* event ) +{ + double centerX = double( contentsX() + 0.5 * visibleWidth() ) / double( contentsWidth() ); + double centerY = double( contentsY() + 0.5 * visibleHeight() ) / double( contentsHeight() ); + + QScrollView::resizeEvent( event ); + if( !m_pixmap ) + m_pixmap = new QPixmap( width(), height() ); + else + m_pixmap->resize( width(), height() ); + + VPainter *p = m_view->painterFactory()->painter(); + p->resize( width(), height() ); + p->clear( QColor( 195, 194, 193 ) ); + setViewport( centerX, centerY ); +} + +void +VCanvas::slotContentsMoving( int /*x*/, int /*y*/ ) +{ + emit viewportChanged(); +} + +void +VCanvas::dragEnterEvent( QDragEnterEvent *e ) +{ + e->accept( KarbonDrag::canDecode( e ) || KColorDrag::canDecode( e ) ); +} + +void +VCanvas::dropEvent( QDropEvent *e ) +{ + m_view->dropEvent( e ); +} + +#include "vcanvas.moc" + diff --git a/karbon/widgets/vcanvas.h b/karbon/widgets/vcanvas.h new file mode 100644 index 00000000..d0446087 --- /dev/null +++ b/karbon/widgets/vcanvas.h @@ -0,0 +1,101 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VCANVAS_H__ +#define __VCANVAS_H__ + + +#include <qscrollview.h> +#include <koffice_export.h> +class KarbonPart; +class KarbonView; +class KoRect; +class KoPoint; +class VPainter; + +// The canvas is a QScrollView. + +class KARBONCOMMON_EXPORT VCanvas : public QScrollView +{ + Q_OBJECT +public: + VCanvas( QWidget *parent, KarbonView* view, KarbonPart* part ); + virtual ~VCanvas(); + + void repaintAll( const KoRect & ); + void repaintAll( bool drawVObjects = true ); + + QPixmap *pixmap() { return m_pixmap; } + + /** + * Sets mouse position to point p. + */ + void setPos( const KoPoint& p ); + + KoPoint toViewport( const KoPoint & ) const; + KoPoint toContents( const KoPoint & ) const; + KoRect boundingBox() const; + + /** + * Adjusts the viewport top-left position. This doesn't change the zoom level. + * Note that centerX and centerY is a value between 0.0 and 1.0, indicating a + * percentage of the total width/height. Thus centerX/centerY indicates the + * center of the viewport. + */ + void setViewport( double centerX, double centerY ); + + /** + * Sets the canvas viewport rectangle to rect. The zoom level is adjusted for this, if + * needed. + */ + void setViewportRect( const KoRect &rect ); + + int pageOffsetX() const; + int pageOffsetY() const; + + KoPoint snapToGrid( const KoPoint & ); + +protected: + virtual void dragEnterEvent( QDragEnterEvent * ); + virtual void dropEvent( QDropEvent * ); + virtual void focusInEvent( QFocusEvent * ); + virtual void viewportPaintEvent( QPaintEvent* ); + virtual void drawContents( QPainter* painter, int clipx, int clipy, + int clipw, int cliph ); + void drawDocument( QPainter* painter, const KoRect& rect, bool drawVObjects = true ); + + virtual void resizeEvent( QResizeEvent* event ); + + virtual bool eventFilter( QObject* object, QEvent* event ); + + void setYMirroring( VPainter * ); + +private slots: + void slotContentsMoving( int , int ); + +signals: + void viewportChanged(); + +private: + QPixmap *m_pixmap; + KarbonPart* m_part; + KarbonView* m_view; +}; + +#endif diff --git a/karbon/widgets/vcolorslider.cc b/karbon/widgets/vcolorslider.cc new file mode 100644 index 00000000..cd11951b --- /dev/null +++ b/karbon/widgets/vcolorslider.cc @@ -0,0 +1,149 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vcolorslider.cc */ + +#include <qlayout.h> +#include <qlabel.h> +#include <knuminput.h> +#include <kselect.h> + +#include "vcolorslider.h" + +VColorSlider::VColorSlider( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + init(); +} + +// Label, left color, right color, min, max, value ... +VColorSlider::VColorSlider( const QString& label, const QColor& col1, + const QColor& col2, int min, int max, int value, QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + init(); + setLabel( label ); + setColors( col1, col2 ); + setMinValue( min ); + setMaxValue( max ); + setValue( value ); +} + +VColorSlider::~VColorSlider() +{ +} + +void VColorSlider::init() +{ + m_isDragging = false; + QHBoxLayout *layout = new QHBoxLayout( this, 3 ); + + m_label = new QLabel( this ); + m_gradientSelect = new KGradientSelector( KSelector::Horizontal, this ); + m_spinBox = new KIntSpinBox( this ); + + layout->addWidget( m_label ); + layout->addWidget( m_gradientSelect, 2 ); + layout->addWidget( m_spinBox ); + + setValue( 0 ); + setMinValue( 0 ); + setMaxValue( 255 ); + + connect( m_spinBox, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_spinBox( int ) ) ); + connect( m_gradientSelect, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_gradientSelect( int ) ) ); + + m_gradientSelect->installEventFilter( this ); + + layout->activate(); +} + +void VColorSlider::setLabel( const QString& label ) +{ + m_label->setText( label ); +} + +void VColorSlider::setColors( const QColor& color1, const QColor& color2 ) +{ + m_gradientSelect->setColors( color1, color2 ); +} + +void VColorSlider::setValue( int value ) +{ + m_spinBox->setValue( value ); + m_gradientSelect->setValue( (m_maxValue - value) + m_minValue ); +} + +void VColorSlider::setMinValue( int value ) +{ + m_minValue = value; + m_spinBox->setMinValue( value ); + m_gradientSelect->setMinValue( value ); +} + +void VColorSlider::setMaxValue( int value ) +{ + m_maxValue = value; + m_spinBox->setMaxValue( value ); + m_gradientSelect->setMaxValue( value ); +} + +int VColorSlider::value() +{ + return( m_spinBox->value() ); +} + +void VColorSlider::updateFrom_spinBox( int value ) +{ + if ( value != m_gradientSelect->value() ) + { + disconnect( m_gradientSelect, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_gradientSelect( int ) ) ); + m_gradientSelect->setValue( (m_maxValue - value) + m_minValue ); + connect( m_gradientSelect, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_gradientSelect( int ) ) ); + emit valueChanged( value ); + } +} + +void VColorSlider::updateFrom_gradientSelect( int value ) +{ + value = (m_maxValue - value) + m_minValue; + if ( value != m_spinBox->value() ) + { + disconnect( m_spinBox, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_spinBox( int ) ) ); + m_spinBox->setValue( value ); + connect( m_spinBox, SIGNAL( valueChanged ( int ) ), this, SLOT( updateFrom_spinBox( int ) ) ); + emit valueChanged( value ); + } +} + +bool VColorSlider::eventFilter( QObject *obj, QEvent *ev ) +{ + if( obj == m_gradientSelect ) + { + if ( ev->type() == QEvent::MouseButtonPress ) + m_isDragging = true; + else if( ev->type() == QEvent::MouseButtonRelease ) + m_isDragging = false; + } + return FALSE; +} + +#include "vcolorslider.moc" + diff --git a/karbon/widgets/vcolorslider.h b/karbon/widgets/vcolorslider.h new file mode 100644 index 00000000..82c7f6ec --- /dev/null +++ b/karbon/widgets/vcolorslider.h @@ -0,0 +1,141 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vcolorslider.h */ +#ifndef VCOLORSLIDER_H +#define VCOLORSLIDER_H + +#include <qwidget.h> + +class QLabel; +class KIntSpinBox; +class KGradientSelector; + +/** + * This is the color slider widget that is used to select color or color components. + * It combines a label, a gradient selector and a spinbox. + */ +class VColorSlider : public QWidget +{ + Q_OBJECT +public: + /** + * Constructs a new color slider. + * + * @param parent the parent widget + * @param name the slider's name + */ + VColorSlider( QWidget* parent = 0L, const char* name = 0L ); + + /** + * Constructs a new color slider. + * + * @param label the label text + * @param col1 the left color + * @param col2 the right color + * @param min the minimum value + * @param max the maximum value + * @param value the actual value + * @param parent the parent widget + * @param name the slider's name + */ + VColorSlider( const QString& label, const QColor& col1, const QColor& col2, + int min, int max, int value, QWidget* parent = 0L, const char* name = 0L ); + + /** Destroys the color slider */ + ~VColorSlider(); + + /** + * Reflects if the slider is still being dragged while the color changes + * + * @return true if slider is still dragged, else false + */ + bool isDragging() { return m_isDragging; } +public slots: + + /** + * Sets the description of the slider + * + * @param label the new label text + */ + virtual void setLabel( const QString& label ); + + /** + * Sets the colors for the slider. + * + * @param color1 the new left color + * @param color2 the new right color + */ + virtual void setColors( const QColor& color1, const QColor& color2 ); + + /** + * Sets the value of the spinbox (and the value of the vcolorslider). + * + * @param value the new value + */ + virtual void setValue( int value ); + + /** + * Sets the minimum value of the spinbox and slider. + * + * @param value the new minimum value + */ + virtual void setMinValue( int value ); + + /** + * Sets the maximum value of the spinbox and slider. + * + * @param value the new maximum value + */ + virtual void setMaxValue( int value ); + + /** + * Retrieves the actual value of the spinbox and slider. + * + * @return the actual value + */ + int value(); + +private: + void init(); + bool eventFilter( QObject *obj, QEvent *ev ); + QLabel* m_label; + KIntSpinBox* m_spinBox; + KGradientSelector* m_gradientSelect; + bool m_isDragging; + int m_minValue; + int m_maxValue; + +signals: + /** + * Is emitted whenever the slider or spinbox value has changed. + * Use @ref isDragging to know if the slider is still being dragged. + * + * @param value the actual value + */ + void valueChanged( int value ); + +private slots: + void updateFrom_spinBox( int ); + void updateFrom_gradientSelect( int ); +}; + +#endif + diff --git a/karbon/widgets/vgradienttabwidget.cc b/karbon/widgets/vgradienttabwidget.cc new file mode 100644 index 00000000..44bb53bc --- /dev/null +++ b/karbon/widgets/vgradienttabwidget.cc @@ -0,0 +1,343 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qpainter.h> +#include <qlayout.h> +#include <qgroupbox.h> +#include <qpushbutton.h> +#include <qfileinfo.h> +#include <qpixmap.h> + +#include <knuminput.h> +#include <kcombobox.h> +#include <klocale.h> +#include <klistbox.h> +#include <kiconloader.h> + +#include "vgradientwidget.h" +#include "vgradienttabwidget.h" +#include "karbon_resourceserver.h" +#include "vkopainter.h" +#include "vfill.h" + +VGradientListItem::VGradientListItem( const VGradient& gradient, QString filename ) + : QListBoxItem( 0L ), m_filename( filename ) +{ + m_gradient = new VGradient( gradient ); + + m_pixmap.resize( 200, 16 ); + VKoPainter gp( &m_pixmap, m_pixmap.width(), m_pixmap.height() ); + gp.setRasterOp( Qt::XorROP ); + gp.newPath(); + VGradient grad( *m_gradient ); + grad.setOrigin( KoPoint( 0, 0 ) ); + grad.setVector( KoPoint( m_pixmap.width() - 1, 0 ) ); + grad.setType( VGradient::linear ); + VFill fill; + fill.gradient() = grad; + fill.setType( VFill::grad ); + gp.setBrush( fill ); + gp.moveTo( KoPoint( 0, 0 ) ); + gp.lineTo( KoPoint( 0, m_pixmap.height() - 1 ) ); + gp.lineTo( KoPoint( m_pixmap.width() - 1, m_pixmap.height() - 1 ) ); + gp.lineTo( KoPoint( m_pixmap.width() - 1, 0 ) ); + gp.lineTo( KoPoint( 0, 0 ) ); + gp.fillPath(); + gp.end(); + + m_delete = QFileInfo( filename ).isWritable(); +} // VGradientListItem::VGradientListItem + +VGradientListItem::VGradientListItem( const VGradientListItem& gradient ) + : QListBoxItem( 0L ) +{ + m_pixmap = gradient.m_pixmap; + m_delete = gradient.m_delete; + m_gradient = new VGradient( *gradient.gradient() ); + m_filename = gradient.m_filename; +} // VGradientListItem::VGradientListItem + +VGradientListItem::~VGradientListItem() +{ + delete m_gradient; +} // VGradientListItem::~VGradientListItem + +int VGradientListItem::width( const QListBox* lb ) const +{ + return lb->width() - 25; +} // VGradientListItem::width + +void VGradientListItem::paint( QPainter* painter ) +{ + painter->save(); + painter->setRasterOp( Qt::CopyROP ); + QRect r ( 0, 0, width( listBox() ), height( listBox() ) ); + painter->scale( ( (float)( width( listBox() ) ) ) / 200., 1. ); + painter->drawPixmap( 0, 0, m_pixmap ); + painter->restore(); + if ( isSelected() ) + painter->setPen( listBox()->colorGroup().highlightedText() ); + else + painter->setPen( listBox()->colorGroup().base() ); + painter->drawRect( r ); + painter->flush(); +} // VGradientListItem::paint + +VGradientPreview::VGradientPreview( VGradient& gradient, double& opacity, QWidget* parent, const char* name ) + : QWidget( parent, name ), m_gradient( &gradient ), m_opacity( &opacity ) +{ + setBackgroundMode( Qt::NoBackground ); + setMinimumSize( 70, 70 ); +} // VGradientPreview::VGradientPreview + +VGradientPreview::~VGradientPreview() +{ +} // VGradientPreview::~VGradientPreview + +void VGradientPreview::paintEvent( QPaintEvent* ) +{ + QPixmap pixmap( width(), height() ); + VKoPainter gp( &pixmap, width(), height() ); + gp.setRasterOp( Qt::XorROP ); + gp.newPath(); + VGradient gradient( *m_gradient ); + if( gradient.type() == VGradient::radial || gradient.type() == VGradient::conic ) + { + gradient.setOrigin( KoPoint( width() / 2, height() / 2 ) ); + gradient.setFocalPoint( KoPoint( width() / 2, height() / 2 ) ); + gradient.setVector( KoPoint( width() / 4, height() / 4 ) ); + } + else + { + gradient.setOrigin( KoPoint( width() / 3, 2 * ( height() / 3 ) ) ); + gradient.setVector( KoPoint( 2 * ( width() / 3 ), height() / 3 ) ); + } + VFill fill; + KIconLoader il; + fill.pattern() = VPattern( il.iconPath( "karbon.png", KIcon::Small ) ); + fill.setType( VFill::patt ); + gp.setBrush( fill ); + gp.fillPath(); + fill.gradient() = gradient; + fill.setType( VFill::grad ); + VColor c = fill.color(); + c.setOpacity( *m_opacity ); + fill.setColor( c, false ); + gp.setBrush( fill ); + gp.moveTo( KoPoint( 2, 2 ) ); + gp.lineTo( KoPoint( 2, height() - 2 ) ); + gp.lineTo( KoPoint( width() - 2, height() - 2 ) ); + gp.lineTo( KoPoint( width() - 2, 2 ) ); + gp.lineTo( KoPoint( 2, 2 ) ); + gp.fillPath(); + gp.end(); + + QPainter p( &pixmap ); + + p.setPen( colorGroup().light() ); + p.moveTo( 1, height() - 1 ); + p.lineTo( 1, 1 ); + p.lineTo( width() - 1, 1 ); + p.lineTo( width() - 1, height() - 1 ); + p.lineTo( 1, height() - 1 ); + p.setPen( colorGroup().dark() ); + p.moveTo( 0, height() - 1 ); + p.lineTo( 0, 0 ); + p.lineTo( width() - 1, 0 ); + p.moveTo( width() - 2, 2 ); + p.lineTo( width() - 2, height() - 2 ); + p.lineTo( 2, height() - 2 ); + bitBlt( this, 0, 0, &pixmap, 0, 0, width(), height() ); +} // VGradientPreview::paintEvent + +VGradientTabWidget::VGradientTabWidget( VGradient& gradient, KarbonResourceServer* server, QWidget* parent, const char* name ) + : QTabWidget( parent, name ), m_gradient( gradient ), m_resourceServer( server ) +{ + setupUI(); + setupConnections(); + initUI(); +} // VGradientTabWidget::VGradientTabWidget + +VGradientTabWidget::~VGradientTabWidget() +{ +} // VGradientTabWidget::~VGradientTabWidget + +void VGradientTabWidget::setupUI() +{ + m_editGroup = new QGroupBox( i18n( "Edit Gradient" ) ); + QGridLayout* editLayout = new QGridLayout( m_editGroup, 7, 3 ); + editLayout->setSpacing( 3 ); + editLayout->setMargin( 6 ); + editLayout->addRowSpacing( 0, 12 ); + editLayout->addMultiCellWidget( m_gradientPreview = new VGradientPreview( m_gradient, m_gradOpacity, m_editGroup ), 1, 3, 0, 0 ); + editLayout->addWidget( new QLabel( i18n( "Type:" ), m_editGroup ), 1, 1 ); + editLayout->addWidget( new QLabel( i18n( "Repeat:" ), m_editGroup ), 2, 1 ); + editLayout->addWidget( new QLabel( i18n( "Target:" ), m_editGroup ), 3, 1 ); + editLayout->addWidget( m_gradientType = new KComboBox( false, m_editGroup ), 1, 2 ); + m_gradientType->insertItem( i18n( "Linear" ), 0 ); + m_gradientType->insertItem( i18n( "Radial" ), 1 ); + m_gradientType->insertItem( i18n( "Conical" ), 2 ); + editLayout->addWidget( m_gradientRepeat = new KComboBox( false, m_editGroup ), 2, 2 ); + m_gradientRepeat->insertItem( i18n( "None" ), 0 ); + m_gradientRepeat->insertItem( i18n( "Reflect" ), 1 ); + m_gradientRepeat->insertItem( i18n( "Repeat" ), 2 ); + editLayout->addWidget( m_gradientTarget = new KComboBox( false, m_editGroup ), 3, 2 ); + m_gradientTarget->insertItem( i18n( "Stroke" ), 0 ); + m_gradientTarget->insertItem( i18n( "Fill" ), 1 ); + editLayout->addMultiCellWidget( m_addToPredefs = new QPushButton( i18n( "&Add to Predefined Gradients" ), m_editGroup ), 6, 6, 0, 2 ); + editLayout->addMultiCellWidget( m_gradientWidget = new VGradientWidget( m_gradient, m_editGroup ), 4, 4, 0, 2 ); + editLayout->addWidget( new QLabel( i18n( "Overall opacity:" ), m_editGroup ), 5, 0 ); + m_opacity = new KIntNumInput( 100, m_editGroup ); + m_opacity->setRange( 0, 100, 1, true ); + m_opacity->setValue( 100 ); + editLayout->addMultiCellWidget( m_opacity, 5, 5, 1, 2 ); + addTab( m_editGroup, i18n( "Edit" ) ); + + QGroupBox* predefGroup = new QGroupBox( i18n( "Predefined Gradients" ) ); + QGridLayout* predefLayout = new QGridLayout( predefGroup, 3, 2 ); + predefLayout->setSpacing( 3 ); + predefLayout->setMargin( 6 ); + predefLayout->addRowSpacing( 0, 12 ); + predefLayout->addMultiCellWidget( m_predefGradientsView = new KListBox( predefGroup ), 1, 1, 0, 2 ); + predefLayout->addWidget( m_predefDelete = new QPushButton( i18n( "&Delete" ), predefGroup ), 2, 0 ); + predefLayout->addWidget( m_predefImport = new QPushButton( i18n( "&Import" ), predefGroup ), 2, 1 ); + m_predefImport->setEnabled( false ); + addTab( predefGroup, i18n( "Predefined" ) ); +} // VGradientTabWidget::setupUI + +void VGradientTabWidget::setupConnections() +{ + connect( m_gradientType, SIGNAL( activated( int ) ), this, SLOT( combosChange( int ) ) ); + connect( m_gradientRepeat, SIGNAL( activated( int ) ), this, SLOT( combosChange( int ) ) ); + connect( m_gradientWidget, SIGNAL( changed() ), m_gradientPreview, SLOT( update() ) ); + connect( m_addToPredefs, SIGNAL( clicked() ), this, SLOT( addGradientToPredefs() ) ); + connect( m_predefGradientsView, SIGNAL( doubleClicked( QListBoxItem *, const QPoint & ) ), this, SLOT( changeToPredef( QListBoxItem* ) ) ); + connect( m_predefDelete, SIGNAL( clicked() ), this, SLOT( deletePredef() ) ); + connect( m_opacity, SIGNAL( valueChanged( int ) ), this, SLOT( opacityChanged( int ) ) ); +} // VGradientTabWidget::setupConnection + +void VGradientTabWidget::initUI() +{ + m_gradientType->setCurrentItem( m_gradient.type() ); + m_gradientRepeat->setCurrentItem( m_gradient.repeatMethod() ); + m_gradientTarget->setCurrentItem( FILL ); + m_opacity->setValue( 100 ); + + m_predefGradientsView->clear(); + QPtrList<VGradientListItem>* gradientList = m_resourceServer->gradients(); + if( gradientList->count() > 0 ) + for( VGradientListItem* g = gradientList->first(); g != NULL; g = gradientList->next() ) + m_predefGradientsView->insertItem( new VGradientListItem( *g ) ); +} // VGradientTabWidget::initUI + +double +VGradientTabWidget::opacity() const +{ + return m_opacity->value() / 100.0; +} + +void +VGradientTabWidget::setOpacity( double opacity ) +{ + if( opacity < 0.0 || opacity > 1.0 ) + return; + + m_gradOpacity = opacity; + m_opacity->setValue( int(opacity*100.0) ); +} + +const VGradient& +VGradientTabWidget::gradient() +{ + return m_gradient; +} // VGradientTabWidget::gradient + +void VGradientTabWidget::setGradient( VGradient& gradient ) +{ + m_gradient = gradient; + + initUI(); +} // VGradientTabWidget::setGradient + +VGradientTabWidget::VGradientTarget VGradientTabWidget::target() +{ + return (VGradientTarget)m_gradientTarget->currentItem(); +} // VGradientTabWidget::target + +void VGradientTabWidget::setTarget( VGradientTarget target ) +{ + m_gradientTarget->setCurrentItem( target ); +} // VGradientTabWidget::setTarget + +void VGradientTabWidget::combosChange( int ) +{ + m_gradient.setType( (VGradient::VGradientType)m_gradientType->currentItem() ); + m_gradient.setRepeatMethod( (VGradient::VGradientRepeatMethod)m_gradientRepeat->currentItem() ); + + m_gradientPreview->update(); +} // VGradientTabWidget::combosChange + +void VGradientTabWidget::opacityChanged( int value ) +{ + m_gradOpacity = value / 100.0; + m_gradientPreview->update(); +} + +void VGradientTabWidget::addGradientToPredefs() +{ + VGradientListItem* item = m_resourceServer->addGradient( new VGradient( m_gradient ) ); + m_predefGradientsView->insertItem( item ); +} // VGradientTabWidget::addGradientToPredefs() + +void VGradientTabWidget::predefSelected( QListBoxItem* item ) +{ + if( item ) + { + VGradientListItem* gradientItem = (VGradientListItem*)item; + m_predefDelete->setEnabled( gradientItem->canDelete() ); + } +} // VGradientTabWidget::predefSelected + +void VGradientTabWidget::changeToPredef( QListBoxItem* item ) +{ + if( item ) + { + VGradientListItem* gradientItem = (VGradientListItem*)item; + m_gradient = *gradientItem->gradient(); + m_gradientType->setCurrentItem( m_gradient.type() ); + m_gradientRepeat->setCurrentItem( m_gradient.repeatMethod() ); + m_opacity->setValue( 100 ); + m_gradientPreview->update(); + m_gradientWidget->update(); + showPage( m_editGroup ); + } +} // VGradientTabWidget::changeToPredef + +void VGradientTabWidget::deletePredef() +{ + int i = m_predefGradientsView->currentItem(); + if( !m_predefGradientsView->item( i ) ) + return; + m_resourceServer->removeGradient( (VGradientListItem*)m_predefGradientsView->item( i ) ); + m_predefGradientsView->removeItem( i ); +} // VGradientTabWidget::deletePredef + +#include "vgradienttabwidget.moc" + diff --git a/karbon/widgets/vgradienttabwidget.h b/karbon/widgets/vgradienttabwidget.h new file mode 100644 index 00000000..2c60cee3 --- /dev/null +++ b/karbon/widgets/vgradienttabwidget.h @@ -0,0 +1,131 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef _VGRADIENTTABWIDGET_H_ +#define _VGRADIENTTABWIDGET_H_ + +#include <qwidget.h> +#include <qtabwidget.h> +#include <qlistbox.h> +#include <koffice_export.h> +#include "vgradient.h" + +class KComboBox; +class VGradientWidget; +class KListBox; +class KIntNumInput; +class QPushButton; +class QGroupBox; +class KarbonResourceServer; + + +class VGradientListItem : public QListBoxItem +{ +public: + VGradientListItem( const VGradient& gradient, QString filename ); + VGradientListItem( const VGradientListItem& ); + ~VGradientListItem(); + + QPixmap& pixmap() { return m_pixmap; } + const VGradient* gradient() const { return m_gradient; } + QString filename() { return m_filename; } + bool canDelete() { return m_delete; } + + virtual int height( const QListBox* ) const { return 16; } + virtual int width( const QListBox* lb ) const; + +protected: + virtual void paint( QPainter* p ); + +private: + VGradient *m_gradient; + QPixmap m_pixmap; + QString m_filename; + bool m_delete; +}; // VGradientListItem + +class VGradientPreview : public QWidget +{ + public: + VGradientPreview( VGradient& gradient, double& opacity, QWidget* parent = 0L, const char* name = 0L ); + ~VGradientPreview(); + + virtual void paintEvent( QPaintEvent* ); + + protected: + VGradient* m_gradient; + double* m_opacity; +}; // VGradientPreview + +class KARBONBASE_EXPORT VGradientTabWidget : public QTabWidget +{ + Q_OBJECT + + public: + enum VGradientTarget { + STROKE, + FILL + }; + + VGradientTabWidget( VGradient& gradient, KarbonResourceServer* server, QWidget* parent = 0L, const char* name = 0L ); + ~VGradientTabWidget(); + + const VGradient& gradient(); + void setGradient( VGradient& gradient ); + + VGradientTarget target(); + void setTarget( VGradientTarget target ); + + double opacity() const; + void setOpacity( double opacity ); + + public slots: + void combosChange( int ); + void addGradientToPredefs(); + void changeToPredef( QListBoxItem* ); + void predefSelected( QListBoxItem* ); + void deletePredef(); + void opacityChanged( int ); + + protected: + void setupUI(); + void initUI(); + void setupConnections(); + + private: + QGroupBox *m_editGroup; + VGradientWidget *m_gradientWidget; + KComboBox *m_gradientTarget; + KComboBox *m_gradientRepeat; + KComboBox *m_gradientType; + VGradientPreview *m_gradientPreview; + KListBox *m_predefGradientsView; + QPushButton *m_predefDelete; + QPushButton *m_predefImport; + QPushButton *m_addToPredefs; + KIntNumInput *m_opacity; + + VGradient m_gradient; + /** The predefined gradients list. */ + KarbonResourceServer* m_resourceServer; + double m_gradOpacity; +}; // VGradientTabWidget + +#endif /* _VGRADIENTTABWIDGET_H_ */ diff --git a/karbon/widgets/vgradientwidget.cc b/karbon/widgets/vgradientwidget.cc new file mode 100644 index 00000000..25e29cd7 --- /dev/null +++ b/karbon/widgets/vgradientwidget.cc @@ -0,0 +1,309 @@ +/* This file is part of the KDE project + Copyright (C) 2001, The Karbon Developers + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qlabel.h> +#include <qframe.h> +#include <qbitmap.h> + +#include <kcolorbutton.h> +#include <kcombobox.h> +#include <klocale.h> +#include <qpainter.h> +#include <kiconloader.h> + +#include "vgradientwidget.h" +#include "vcolordlg.h" +#include "vfill.h" +#include "vkopainter.h" +#include "vcursor.h" + +#define midPoint_width 7 +#define midPoint_height 10 +static unsigned char midPoint_bits[] = { + 0x08, 0x08, 0x1c, 0x1c, 0x2a, 0x2a, 0x08, 0x08, 0x08, 0x08 +}; + +#define colorStopBorder_width 11 +#define colorStopBorder_height 11 +static unsigned char colorStopBorder_bits[] = { + 0x20, 0x00, 0x50, 0x00, 0x50, 0x00, 0x88, 0x00, 0x88, 0x00, 0x04, 0x01, + 0x04, 0x01, 0x02, 0x02, 0x02, 0x02, 0x01, 0x04, 0xff, 0x07 +}; + +#define colorStop_width 9 +#define colorStop_height 10 +static unsigned char colorStop_bits[] = { + 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7c, 0x00, + 0x7c, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xff, 0x01 +}; + +VGradientWidget::VGradientWidget( VGradient& gradient, QWidget* parent, const char* name ) + : QWidget( parent, name ), m_gradient( &gradient ) +{ + setBackgroundMode( Qt::NoBackground ); + setMinimumSize( 105, 35 ); +} // VGradientWidget::VGradientWidget + +VGradientWidget::~VGradientWidget() +{ +} // VGradientWidget::~VGradientWidget + +void VGradientWidget::paintColorStop( QPainter& p, int x, VColor& color ) +{ + QBitmap bitmap; + + bitmap = QBitmap( colorStop_width, colorStop_height, colorStop_bits, true ); + bitmap.setMask( bitmap ); + p.setPen( color ); + p.drawPixmap( x - 4, 1, bitmap ); + + bitmap = QBitmap( colorStopBorder_width, colorStopBorder_height, colorStopBorder_bits, true ); + bitmap.setMask( bitmap ); + p.setPen( Qt::black ); + p.drawPixmap( x - 5, 1, bitmap ); +} // VGradientWidget::paintColorStop + +void VGradientWidget::paintMidPoint( QPainter& p, int x ) +{ + QBitmap bitmap( midPoint_width, midPoint_height, midPoint_bits, true ); + bitmap.setMask( bitmap ); + p.setPen( Qt::black ); + p.drawPixmap( x - 3, 1, bitmap ); +} // VGradientWidget::paintMidPoint + +void VGradientWidget::paintEvent( QPaintEvent* ) +{ + int w = width() - 4; // available width for gradient and points + int h = height() - 7; // available height for gradient and points + int ph = colorStopBorder_height + 2; // point marker height + int gh = h - ph; // gradient area height + + QPixmap pixmap( width(), height() ); + VKoPainter gp( &pixmap, width(), height() ); + gp.setRasterOp( Qt::XorROP ); + VGradient gradient( *m_gradient ); + gradient.setType( VGradient::linear ); + gradient.setOrigin( KoPoint( 2, 2 ) ); + gradient.setFocalPoint( KoPoint( 2, 2 ) ); + gradient.setVector( KoPoint( 2 + w, 2 ) ); + VFill fill; + KIconLoader il; + fill.pattern() = VPattern( il.iconPath( "karbon.png", KIcon::Small ) ); + fill.setType( VFill::patt ); + gp.setBrush( fill ); + gp.drawRect( KoRect( 2, 2, w, gh ) ); + fill.gradient() = gradient; + fill.setType( VFill::grad ); + gp.setBrush( fill ); + gp.drawRect( KoRect( 2, 2, w, gh ) ); + gp.end(); + + QPainter p( &pixmap ); + + p.setPen( colorGroup().light() ); + // light frame around widget + p.moveTo( 1, height() - 1 ); + p.lineTo( 1, 1 ); + p.lineTo( width() - 1, 1 ); + p.lineTo( width() - 1, height() - 1 ); + p.lineTo( 1, height() - 1 ); + + // light line between gradient and point area + p.moveTo( 1, 3 + gh ); + p.lineTo( width() - 1, 3 + gh ); + + p.setPen( colorGroup().dark() ); + // left-top frame around widget + p.moveTo( 0, height() - 1 ); + p.lineTo( 0, 0 ); + p.lineTo( width() - 1, 0 ); + + // right-bottom from around gradient + p.moveTo( width() - 2, 2 ); + p.lineTo( width() - 2, 2 + gh ); + p.lineTo( 2, 2 + gh ); + + // upper line around point area + p.moveTo( 1, height() - 3 - ph ); + p.lineTo( width() - 1, height() - 3 - ph ); + + // right-bottom line around point area + p.moveTo( width() - 2, height() - ph - 1 ); + p.lineTo( width() - 2, height() - 2 ); + p.lineTo( 2, height() - 2 ); + + m_pntArea.setRect( 2, height() - ph - 2, w, ph ); + // clear point area + p.fillRect( m_pntArea.x(), m_pntArea.y(), m_pntArea.width(), m_pntArea.height(), colorGroup().background() ); + + p.setClipRect( m_pntArea.x(), m_pntArea.y(), m_pntArea.width(), m_pntArea.height() ); + p.translate( m_pntArea.x(), m_pntArea.y() ); + + QPtrList<VColorStop>& colorStops = m_gradient->m_colorStops; + if( colorStops.count() > 1 ) + { + VColorStop* stop, *nextstop; + for( stop = colorStops.first(), nextstop = colorStops.next(); + nextstop; stop = nextstop, nextstop = colorStops.next() ) + { + paintColorStop( p, (int)( stop->rampPoint * m_pntArea.width() ), stop->color ); + paintMidPoint( p, (int)(( stop->rampPoint + ( nextstop->rampPoint - stop->rampPoint ) * stop->midPoint ) * m_pntArea.width() ) ); + } + paintColorStop( p, int( stop->rampPoint * w ), stop->color ); + } + p.end(); + bitBlt( this, 0, 0, &pixmap, 0, 0, width(), height() ); +} // VGradientWidget::paintEvent + +void VGradientWidget::mousePressEvent( QMouseEvent* e ) +{ + if( ! m_pntArea.contains( e->x(), e->y() ) ) + return; + + QPtrList<VColorStop>& colorStops = m_gradient->m_colorStops; + + currentPoint = 0; + + int x = e->x() - m_pntArea.left(); + + int i = colorStops.count() - 1; + VColorStop *stop, *nextstop = 0; + for( stop = colorStops.last(); i >= 0; i--, stop = colorStops.prev() ) + { + int r = int( stop->rampPoint * m_pntArea.width() ); + if( nextstop ) + { + int m = int( ( stop->rampPoint + ( nextstop->rampPoint - stop->rampPoint ) * stop->midPoint ) * m_pntArea.width() ); + if( ( x > m - 5 ) && ( x < m + 5 ) ) + { + // found mid point at position + currentPoint = 2 * i + 2; + if( e->button() == Qt::LeftButton ) + setCursor( VCursor::horzMove() ); + return; + } + } + if( ( x > r - 5 ) && ( x < r + 5 ) ) + { + // found ramp point at position + currentPoint = 2 * i + 1; + if( e->button() == Qt::LeftButton ) + setCursor( VCursor::horzMove() ); + return; + } + + nextstop = stop; + } +} // VGradientWidget::mousePressEvent + +void VGradientWidget::mouseReleaseEvent( QMouseEvent* e ) +{ + if( e->button() == Qt::RightButton && currentPoint ) + { + if( m_pntArea.contains( e->x(), e->y() ) && ( currentPoint % 2 == 1 ) ) + { + int x = e->x() - m_pntArea.left(); + // check if we are still above the actual ramp point + int r = int( m_gradient->m_colorStops.at( int(0.5 * currentPoint) )->rampPoint * m_pntArea.width() ); + if( ( x > r - 5 ) && ( x < r + 5 ) ) + { + m_gradient->m_colorStops.remove( int(0.5 * currentPoint) ); + update(); + emit changed(); + } + } + } + setCursor( QCursor( Qt::ArrowCursor ) ); +} // VGradientWidget::mouseReleaseEvent + +void VGradientWidget::mouseDoubleClickEvent( QMouseEvent* e ) +{ + if( ! m_pntArea.contains( e->x(), e->y() ) ) + return; + + if( e->button() != Qt::LeftButton ) + return; + + if( currentPoint % 2 == 1 ) + { + // ramp point hit -> change color + VColorDlg* d = new VColorDlg( m_gradient->m_colorStops.at( currentPoint / 2 )->color, this->topLevelWidget() ); + if( d->exec() == QDialog::Accepted ) + { + m_gradient->m_colorStops.at( currentPoint / 2 )->color = d->Color(); + update(); + emit changed(); + } + delete d; + } + else if( currentPoint == 0 ) + { + // now point hit -> create new color stop + VColorDlg* d = new VColorDlg( m_gradient->m_colorStops.at( 0 )->color, this->topLevelWidget() ); + if( d->exec() == QDialog::Accepted ) + { + m_gradient->addStop( d->Color(), (float)( e->x() - 2 ) / ( m_pntArea.width() ), 0.5 ); + update(); + emit changed(); + } + delete d; + } +} // VGradientWidget::mouseDoubleClickEvent + +void VGradientWidget::mouseMoveEvent( QMouseEvent* e ) +{ + if( e->state() & Qt::RightButton ) + return; + + QPtrList<VColorStop>& colorStops = m_gradient->m_colorStops; + + if( currentPoint >= colorStops.count() * 2 ) + return; + + int x = e->x() - m_pntArea.left(); + + if( currentPoint % 2 == 1 ) + { + // move ramp point + int actRP = int( 0.5 * ( currentPoint - 1 ) ); + int prevRP = actRP - 1; + int nextRP = int( 0.5 * ( currentPoint + 1 ) ); + // Clip the color stop between to others. + x = kMin( x, ( actRP < int( colorStops.count() - 1 ) ) ? int( colorStops.at( nextRP )->rampPoint * m_pntArea.width() ) : m_pntArea.width() ); + x = kMax( x, ( actRP > 0 ) ? int( colorStops.at( prevRP )->rampPoint * m_pntArea.width() ) : 0 ); + colorStops.at( actRP )->rampPoint = (float)( x ) / m_pntArea.width(); + update(); + emit changed(); + } + else if( currentPoint > 0 ) + { + // move mid point + int prevRP = int( 0.5 * ( currentPoint - 1 ) ); + int nextRP = int( 0.5 * ( currentPoint + 1 ) ); + // Clip the mid point between to ramp points. + x = kMin( x, int( colorStops.at( nextRP )->rampPoint * m_pntArea.width() ) ); + x = kMax( x, int( colorStops.at( prevRP )->rampPoint * m_pntArea.width() ) ); + colorStops.at( prevRP )->midPoint = ( (float)( x ) / m_pntArea.width() - ( colorStops.at( prevRP )->rampPoint ) ) / ( colorStops.at( nextRP )->rampPoint - colorStops.at( prevRP )->rampPoint ); + update(); + emit changed(); + } +} // VGradientWidget::mouseMoveEvent + +#include "vgradientwidget.moc" diff --git a/karbon/widgets/vgradientwidget.h b/karbon/widgets/vgradientwidget.h new file mode 100644 index 00000000..76f7472d --- /dev/null +++ b/karbon/widgets/vgradientwidget.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef _VGRADIENTWIDGET_H_ +#define _VGRADIENTWIDGET_H_ + +#include <qwidget.h> +#include <koffice_export.h> +class VGradient; +class QPainter; +class VColor; + +class KARBONBASE_EXPORT VGradientWidget : public QWidget +{ + Q_OBJECT + +public: + VGradientWidget( VGradient& gradient, QWidget* parent = 0L, const char* name = 0L ); + ~VGradientWidget(); + + virtual void paintEvent( QPaintEvent* ); + +signals: + void changed(); + +protected: + /** mouse events... For color stops manipulation */ + void mousePressEvent( QMouseEvent* ); + void mouseReleaseEvent( QMouseEvent* ); + void mouseDoubleClickEvent( QMouseEvent* ); + void mouseMoveEvent( QMouseEvent* ); + + void paintColorStop( QPainter& p, int x, VColor& color ); + void paintMidPoint( QPainter& p, int x ); + + /** The gradient to modify. */ + VGradient* m_gradient; + /** The point to modify. */ + unsigned int currentPoint; + + QRect m_pntArea; +}; // VGradientWidget + +#endif /* _VGRADIENTWIDGET_H_ */ diff --git a/karbon/widgets/vreference.cc b/karbon/widgets/vreference.cc new file mode 100644 index 00000000..43b0e8b2 --- /dev/null +++ b/karbon/widgets/vreference.cc @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vreference.cc */ + +#include <qbuttongroup.h> +#include <qlayout.h> +#include <qradiobutton.h> + +#include "vreference.h" + +VReference::VReference( QWidget *parent, const char *name ) : QFrame ( parent, name ) +{ + QVBoxLayout* layout = new QVBoxLayout( this ); + mButtonGroup = new QButtonGroup (3, Vertical, this ); + QRadioButton* radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, TopLeft ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, Left ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, BottomLeft ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, Top ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, Center ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, Bottom ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, TopRight ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, Right ); + radio = new QRadioButton ( mButtonGroup ); + mButtonGroup->insert( radio, BottomRight ); + + connect( + mButtonGroup, SIGNAL( clicked( int ) ), + this, SLOT( setReferencePoint( int ) ) ); + + mButtonGroup->setButton( Center ); + layout->addWidget( mButtonGroup ); + layout->activate(); + setReferencePoint( Center ); +} + +void VReference::setReferencePoint ( int i ) +{ + m_referencePoint = i; + emit referencePointChanged( m_referencePoint ); +} + +int VReference::referencePoint() +{ + return( m_referencePoint ); +} + +#include "vreference.moc" + diff --git a/karbon/widgets/vreference.h b/karbon/widgets/vreference.h new file mode 100644 index 00000000..3c6c1a9f --- /dev/null +++ b/karbon/widgets/vreference.h @@ -0,0 +1,61 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* This is the color slider widget that is used to select color or color components */ + +/* vreference.h */ +#ifndef VREFERENCE_H +#define VREFERENCE_H + +#include <qframe.h> + +class QButtonGroup; + +enum Choice +{ + TopLeft, + Left, + BottomLeft, + Top, + Center, + Bottom, + TopRight, + Right, + BottomRight +}; + +class VReference : public QFrame +{ + Q_OBJECT +public: + VReference( QWidget *parent = 0L, const char *name = 0L ); + int referencePoint(); +public slots: + virtual void setReferencePoint ( int ); + +private: + int m_referencePoint; + QButtonGroup* mButtonGroup; +signals: + void referencePointChanged( int referencePoint ); +}; + +#endif + diff --git a/karbon/widgets/vruler.cc b/karbon/widgets/vruler.cc new file mode 100644 index 00000000..0f7c2f62 --- /dev/null +++ b/karbon/widgets/vruler.cc @@ -0,0 +1,332 @@ +/* + * Kivio - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * Copyright (C) 2002 Patrick Julien <freak@codepimps.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <qpainter.h> + +#include "kdebug.h" + +#include "vruler.h" + +#define MARKER_WIDTH 1 +#define MARKER_HEIGHT 20 +#define RULER_SIZE 20 + +const char *VRuler::m_nums[] = { + "70 7 2 1", + " c Black", + "X c None", + "XX XXXXXX XXXX XXXX XXXXXX XXX XXXX XXX XXX XXXX XX", + "X XXX XXXX XXX XXX XX XXX XXXX XXX XXXXXXX XXXXXXXXX XX XXX XX XXX X", + "X XXX XXXXX XXXXXXX XXXXXX XXX X XXX XXXXXX XXXXXXXXX XXX XXX XX XXX X", + "X XXX XXXXX XXXXX XXXXX XXX XX XXX XXX XXXXXX XXXX XXXX X", + "X XXX XXXXX XXXX XXXXXXXXX XX XXXXXX XX XXX XXXX XXXX XXX XXXXXX X", + "X XXX XXXXX XXX XXXXXX XXX XXXXX XXXXXXX XX XXX XXXX XXXX XXX XXXXX XX", + "XX XXXXXX XXX XXX XXXXXX XXX XXXX XXXXX XXXXX XXXX XXX" +}; + +VRuler::VRuler(Qt::Orientation o, QWidget *parent, const char *name) : super(parent, name, WRepaintNoErase | WResizeNoErase), m_pixmapNums(m_nums) +{ + setBackgroundMode(NoBackground); + setFrameStyle(Box | Sunken); + setLineWidth(1); + setMidLineWidth(0); + m_orientation = o; + m_unit = KoUnit::U_PT; + m_zoom = 1.0; + m_firstVisible = 0; + m_pixmapBuffer = 0; + m_currentPosition = -1; + + if (m_orientation == Qt::Horizontal) { + setFixedHeight(RULER_SIZE); + initMarker(MARKER_WIDTH, MARKER_HEIGHT); + } else { + setFixedWidth(RULER_SIZE); + initMarker(MARKER_HEIGHT, MARKER_WIDTH); + } +} + +VRuler::~VRuler() +{ + delete m_pixmapBuffer; +} + +void VRuler::initMarker(Q_INT32 w, Q_INT32 h) +{ + QPainter p; + + m_pixmapMarker.resize(w, h); + p.begin(&m_pixmapMarker); + p.setPen(blue); + p.eraseRect(0, 0, w, h); + p.drawLine(0, 0, w - 1, h - 1); + p.end(); +} + +void VRuler::recalculateSize() +{ + Q_INT32 w; + Q_INT32 h; + + if (m_pixmapBuffer) { + delete m_pixmapBuffer; + m_pixmapBuffer = 0; + } + + if (m_orientation == Qt::Horizontal) { + w = width(); + h = RULER_SIZE; + } else { + w = RULER_SIZE; + h = height(); + } + + m_pixmapBuffer = new QPixmap(w, h); + Q_CHECK_PTR(m_pixmapBuffer); + + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); +} + +KoUnit::Unit VRuler::unit() const +{ + return m_unit; +} + +void VRuler::setUnit(KoUnit::Unit u) +{ + m_unit = u; + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); + repaint(); +} + +void VRuler::setZoom(double zoom) +{ + m_zoom = zoom; + recalculateSize(); + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); + repaint(); +} + +void VRuler::updatePointer(Q_INT32 x, Q_INT32 y) +{ + if (m_pixmapBuffer) { + if (m_orientation == Qt::Horizontal) { + if (m_currentPosition != -1) + repaint(m_currentPosition, 1, MARKER_WIDTH, MARKER_HEIGHT); + + if (x != -1) { + bitBlt(this, x, 1, &m_pixmapMarker, 0, 0, MARKER_WIDTH, MARKER_HEIGHT); + m_currentPosition = x; + } + } else { + if (m_currentPosition != -1) + repaint(1, m_currentPosition, MARKER_HEIGHT, MARKER_WIDTH); + + if (y != -1) { + bitBlt(this, 1, y, &m_pixmapMarker, 0, 0, MARKER_HEIGHT, MARKER_WIDTH); + m_currentPosition = y; + } + } + } +} + +void VRuler::updateVisibleArea(Q_INT32 xpos, Q_INT32 ypos) +{ + if (m_orientation == Qt::Horizontal) + m_firstVisible = xpos; + else + m_firstVisible = ypos; + + //kdDebug() << "--###-- VRuler::updateVisibleArea(" << xpos << ", " << ypos << ")" << endl; + drawRuler(); + repaint(); + updatePointer(m_currentPosition, m_currentPosition); + //kdDebug() << "--###-- VRuler::updatePointer(" << m_currentPosition << ", " << m_currentPosition << ")" << endl; +} + +void VRuler::paintEvent(QPaintEvent *e) +{ + if (m_pixmapBuffer) { + const QRect& rect = e -> rect(); + + bitBlt(this, rect.topLeft(), m_pixmapBuffer, rect); + super::paintEvent(e); + } +} + +void VRuler::drawRuler() +{ + QPainter p; + QString buf; + Q_INT32 st1 = 0; + Q_INT32 st2 = 0; + Q_INT32 st3 = 0; + Q_INT32 st4 = 0; + Q_INT32 stt = 0; + + if (!m_pixmapBuffer) + return; + + p.begin(m_pixmapBuffer); + p.setPen(QColor(0x70, 0x70, 0x70)); + p.setBackgroundColor(colorGroup().background()); + p.eraseRect(0, 0, m_pixmapBuffer -> width(), m_pixmapBuffer -> height()); + + switch (m_unit) { + case KoUnit::U_PT: + case KoUnit::U_MM: + case KoUnit::U_DD: + case KoUnit::U_CC: + st1 = 1; + st2 = 5; + st3 = 10; + st4 = 25; + stt = 100; + break; + case KoUnit::U_CM: + case KoUnit::U_PI: + case KoUnit::U_INCH: + st1 = 1; + st2 = 2; + st3 = 5; + st4 = 10; + stt = 1; + break; + default: + break; + } + + Q_INT32 pos = 0; + bool s1 = KoUnit::fromUserValue(st1, m_unit) * m_zoom > 3.0; + bool s2 = KoUnit::fromUserValue(st2, m_unit) * m_zoom > 3.0; + bool s3 = KoUnit::fromUserValue(st3, m_unit) * m_zoom > 3.0; + bool s4 = KoUnit::fromUserValue(st4, m_unit) * m_zoom > 3.0; + + if (m_orientation == Qt::Horizontal) { + // XXX: This was 7 * 4 -- why? what was the idea about having 30 point intervals? + float cx = KoUnit::fromUserValue(100, m_unit) / m_zoom; + Q_INT32 step = qRound(cx);//((Q_INT32)(cx / (float)stt) + 1) * stt; + Q_INT32 start = (Q_INT32)(KoUnit::toUserValue(m_firstVisible, m_unit) / m_zoom); + + do { + pos = (Q_INT32)(KoUnit::fromUserValue(start, m_unit) * m_zoom - m_firstVisible); + + if (!s3 && s4 && start % st4 == 0) + p.drawLine(pos, RULER_SIZE - 9, pos, RULER_SIZE); + + if (s3 && start % st3 == 0) + p.drawLine(pos, RULER_SIZE - 9, pos, RULER_SIZE); + + if (s2 && start % st2 == 0) + p.drawLine(pos, RULER_SIZE - 7, pos, RULER_SIZE); + + if (s1 && start % st1 == 0) + p.drawLine(pos, RULER_SIZE - 5, pos, RULER_SIZE); + + if (step && start % step == 0) { + buf.setNum(QABS(start)); + drawNums(&p, pos, 4, buf, true); + } + + start++; + } while (pos < m_pixmapBuffer -> width()); + } else { + m_firstVisible = 0; + float cx = KoUnit::fromUserValue(100, m_unit) / m_zoom; + Q_INT32 height = m_pixmapBuffer -> height() - 1; + Q_INT32 step = qRound(cx); + Q_INT32 start = (Q_INT32)(KoUnit::toUserValue(m_firstVisible, m_unit) / m_zoom); + + do { + pos = height - (Q_INT32)(KoUnit::fromUserValue(start, m_unit) * m_zoom - m_firstVisible); + + if (!s3 && s4 && start % st4 == 0) + p.drawLine(RULER_SIZE - 9, pos, RULER_SIZE, pos); + + if (s3 && start % st3 == 0) + p.drawLine(RULER_SIZE - 9, pos, RULER_SIZE, pos); + + if (s2 && start % st2 == 0) + p.drawLine(RULER_SIZE - 7, pos, RULER_SIZE, pos); + + if (s1 && start % st1 == 0) + p.drawLine(RULER_SIZE - 5, pos, RULER_SIZE, pos); + + if (step && start % step == 0) { + buf.setNum(QABS(start)); + drawNums(&p, 4, pos, buf, false); + } + + start++; + } while (pos > 0); + } + + p.end(); +} + +void VRuler::resizeEvent(QResizeEvent *) +{ + recalculateSize(); +} + +void VRuler::show() +{ + if (m_orientation == Qt::Horizontal) { + setFixedHeight(RULER_SIZE); + initMarker(MARKER_WIDTH, MARKER_HEIGHT); + } else { + setFixedWidth(RULER_SIZE); + initMarker(MARKER_HEIGHT, MARKER_WIDTH); + } + + super::show(); +} + +void VRuler::hide() +{ + if (m_orientation == Qt::Horizontal) + setFixedHeight(1); + else + setFixedWidth(1); +} + +void VRuler::drawNums(QPainter *p, Q_INT32 x, Q_INT32 y, QString& num, bool orientationHoriz) +{ + if (orientationHoriz) + x -= 7; + else + y -= 8; + + for (Q_UINT32 k = 0; k < num.length(); k++) { + Q_INT32 st = num.at(k).digitValue() * 7; + + p -> drawPixmap(x, y, m_pixmapNums, st, 0, 7, 7); + + if (orientationHoriz) + x += 7; + else + y += 8; + } +} + +#include "vruler.moc" + diff --git a/karbon/widgets/vruler.h b/karbon/widgets/vruler.h new file mode 100644 index 00000000..c03de9a2 --- /dev/null +++ b/karbon/widgets/vruler.h @@ -0,0 +1,77 @@ +/* + * Kivio - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * Copyright (C) 2002 Patrick Julien <freak@codepimps.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef VRULER_H_ +#define VRULER_H_ + +#include <qframe.h> +#include <qpixmap.h> +#include <KoUnit.h> + +// XXX: Make this look more like the KOffice ruler -- the KOffice +// ruler is not quite suited to Krita. Also: start units with 0, +// print every 100 units. + +class QPainter; + +class VRuler : public QFrame { + Q_OBJECT + typedef QFrame super; + +public: + VRuler(Qt::Orientation, QWidget *parent = 0, const char *name = 0); + virtual ~VRuler(); + +public: + KoUnit::Unit unit() const; + +public slots: + void setZoom(double zoom); + void updatePointer(Q_INT32 x, Q_INT32 y); + void updateVisibleArea(Q_INT32 xpos, Q_INT32 ypos); + void setUnit(KoUnit::Unit u); + void hide(); + void show(); + +public: + virtual void paintEvent(QPaintEvent *e); + virtual void resizeEvent(QResizeEvent *e); + +protected: + void recalculateSize(); + void drawRuler(); + void initMarker(Q_INT32 w, Q_INT32 h); + void drawNums(QPainter *gc, Q_INT32 x, Q_INT32 y, QString& num, bool orientationHoriz); + +private: + KoUnit::Unit m_unit; + Qt::Orientation m_orientation; + Q_INT32 m_firstVisible; + Q_INT32 m_currentPosition; + QPixmap *m_pixmapBuffer; + QPixmap m_pixmapMarker; + QPixmap m_pixmapNums; + double m_zoom; + +private: + static const char *m_nums[]; +}; + +#endif // VRULER_H_ + diff --git a/karbon/widgets/vselecttoolbar.cc b/karbon/widgets/vselecttoolbar.cc new file mode 100644 index 00000000..a39650d8 --- /dev/null +++ b/karbon/widgets/vselecttoolbar.cc @@ -0,0 +1,124 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vselecttoolbar.cc */ + +#include <qlabel.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "KoUnitWidgets.h" +#include "vselecttoolbar.h" +#include "karbon_view.h" +#include "karbon_part.h" +#include "vselection.h" +#include "vtransformcmd.h" +#include <KoRect.h> + +VSelectToolBar::VSelectToolBar( KarbonView *view, const char* name ) : KToolBar( view, name ), m_view( view ) +{ + setCaption( i18n( "Object Properties" ) ); + QLabel *x_label = new QLabel( i18n( "X:" ), this, "kde toolbar widget" ); + insertWidget( 0, x_label->width(), x_label ); + m_x = new KoUnitDoubleSpinBox( this, 0.0, 1000.0, 0.5 ); + connect( m_x, SIGNAL( valueChanged( double ) ), this, SLOT( slotXChanged( double ) ) ); + insertWidget( 1, m_x->width(), m_x ); + QLabel *y_label = new QLabel( i18n( "Y:" ), this, "kde toolbar widget" ); + insertWidget( 2, y_label->width(), y_label ); + m_y = new KoUnitDoubleSpinBox( this, 0.0, 1000.0, 0.5 ); + connect( m_y, SIGNAL( valueChanged( double ) ), this, SLOT( slotYChanged( double ) ) ); + insertWidget( 3, m_y->width(), m_y ); + + insertSeparator( 4 ); + QLabel *w_label = new QLabel( i18n( "selection width", "Width:" ), this, "kde toolbar widget" ); + insertWidget( 5, w_label->width(), w_label ); + m_width = new KoUnitDoubleSpinBox( this, 0.0, 1000.0, 0.5 ); + connect( m_width, SIGNAL( valueChanged( double ) ), this, SLOT( slotWidthChanged( double ) ) ); + insertWidget( 6, m_width->width(), m_width ); + QLabel *h_label = new QLabel( i18n( "Height:" ), this, "kde toolbar widget" ); + insertWidget( 7, h_label->width(), h_label ); + m_height = new KoUnitDoubleSpinBox( this, 0.0, 1000.0, 0.5 ); + connect( m_height, SIGNAL( valueChanged( double ) ), this, SLOT( slotHeightChanged( double ) ) ); + insertWidget( 8, m_height->width(), m_height ); + + connect( m_view, SIGNAL( selectionChange() ), this, SLOT( slotSelectionChanged() ) ); +} + +VSelectToolBar::~VSelectToolBar() +{ +} + +void +VSelectToolBar::slotXChanged( double newval ) +{ + double dx = newval - m_view->part()->document().selection()->boundingBox().topLeft().x(); + m_view->part()->addCommand( new VTranslateCmd( &m_view->part()->document(), dx, 0.0 ), true ); +} + +void +VSelectToolBar::slotYChanged( double newval ) +{ + double dy = newval - m_view->part()->document().selection()->boundingBox().topLeft().y(); + m_view->part()->addCommand( new VTranslateCmd( &m_view->part()->document(), 0.0, dy ), true ); +} + +void +VSelectToolBar::slotWidthChanged( double newval ) +{ + if( newval != 0.0 ) + { + double sx = newval / m_view->part()->document().selection()->boundingBox().width(); + KoPoint sp = m_view->part()->document().selection()->boundingBox().topLeft(); + m_view->part()->addCommand( new VScaleCmd( &m_view->part()->document(), sp, sx, 1.0 ), true ); + } +} + +void +VSelectToolBar::slotHeightChanged( double newval ) +{ + if( newval != 0.0 ) + { + double sy = newval / m_view->part()->document().selection()->boundingBox().height(); + KoPoint sp = m_view->part()->document().selection()->boundingBox().bottomLeft(); + m_view->part()->addCommand( new VScaleCmd( &m_view->part()->document(), sp, 1.0, sy ), true ); + } +} + +void +VSelectToolBar::slotSelectionChanged() +{ + m_x->blockSignals( true ); + m_y->blockSignals( true ); + m_width->blockSignals( true ); + m_height->blockSignals( true ); + KoRect rect = m_view->part()->document().selection()->boundingBox(); + m_x->setValue( rect.topLeft().x() ); + m_y->setValue( rect.topLeft().y() ); + m_width->setValue( rect.width() ); + m_height->setValue( rect.height() ); + m_x->blockSignals( false ); + m_y->blockSignals( false ); + m_width->blockSignals( false ); + m_height->blockSignals( false ); +} + +#include "vselecttoolbar.moc" + diff --git a/karbon/widgets/vselecttoolbar.h b/karbon/widgets/vselecttoolbar.h new file mode 100644 index 00000000..376ca134 --- /dev/null +++ b/karbon/widgets/vselecttoolbar.h @@ -0,0 +1,53 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vselecttoolbar.h */ +#ifndef VSELECTTOOLBAR_H +#define VSELECTTOOLBAR_H + +#include <ktoolbar.h> + +class KoUnitDoubleSpinBox; +class KarbonView; + +class VSelectToolBar : public KToolBar +{ + Q_OBJECT +public: + VSelectToolBar( KarbonView *view, const char* name = 0L ); + ~VSelectToolBar(); + +public slots: + void slotSelectionChanged(); + void slotXChanged( double ); + void slotYChanged( double ); + void slotWidthChanged( double ); + void slotHeightChanged( double ); + +private: + KoUnitDoubleSpinBox *m_x; + KoUnitDoubleSpinBox *m_y; + KoUnitDoubleSpinBox *m_width; + KoUnitDoubleSpinBox *m_height; + KarbonView *m_view; +}; + +#endif + diff --git a/karbon/widgets/vsmallpreview.cc b/karbon/widgets/vsmallpreview.cc new file mode 100644 index 00000000..7766f6e9 --- /dev/null +++ b/karbon/widgets/vsmallpreview.cc @@ -0,0 +1,282 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.t-com.hr) + Copyright (C) 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* vsmallpreview.cc */ +#include <qcolor.h> +#include <qframe.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpixmap.h> + +#include <klocale.h> +#include <KoPoint.h> + +#include "vcolor.h" +#include "vfill.h" +#include "vgradient.h" +#include "vkopainter.h" +#include "vpattern.h" +#include "vstroke.h" + +#include "vsmallpreview.h" + +#define FRAMEWIDTH 40 + +VSmallPreview::VSmallPreview( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + /* Create widget layout */ + QHBoxLayout *layout = new QHBoxLayout( this, 4 ); + m_strokeLabel = new QLabel( i18n( "Stroke: None" ), this ); + layout->addWidget( m_strokeLabel ); + m_strokeFrame = new QFrame( this ); + m_strokeFrame->setFixedWidth ( FRAMEWIDTH ); + m_strokeFrame->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain ); + layout->addWidget( m_strokeFrame ); + m_fillLabel = new QLabel( i18n( "Fill: None" ), this ); + layout->addWidget( m_fillLabel ); + m_fillFrame = new QFrame( this ); + m_fillFrame->setFixedWidth ( FRAMEWIDTH ); + m_fillFrame->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain ); + layout->addWidget( m_fillFrame ); + layout->activate(); + + m_fill = VFill(); + m_stroke = VStroke(); +} + +VSmallPreview::~VSmallPreview() +{ +} + +void +VSmallPreview::update( const VStroke &s, const VFill &f ) +{ + if( &f ) + m_fill = f; + else + m_fill = VFill(); + if( &s ) + m_stroke = s; + else + m_stroke = VStroke(); + + drawStroke( m_stroke ); + drawFill( m_fill ); +} + +void +VSmallPreview::paintEvent( QPaintEvent* /*event*/ ) +{ + drawStroke( m_stroke ); + drawFill( m_fill ); +} + +void +VSmallPreview::drawFill( const VFill &f ) +{ + VFill fill; + VStroke stroke; + + QPixmap m_pixmap; + m_pixmap.resize( m_fillFrame->width(), m_fillFrame->height() ); + VKoPainter* m_painter = new VKoPainter( &m_pixmap, m_fillFrame->width(), m_fillFrame->height() ); + + m_painter->begin(); + m_painter->setPen( Qt::NoPen ); + fill.setColor( Qt::white ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_fillFrame->width(), m_fillFrame->height() ) ); + + switch ( f.type() ) + { + case VFill::solid: + { + switch ( f.color().colorSpace() ) + { + case VColor::rgb: + m_fillLabel->setText( i18n( "Fill: RGB") ); break; + case VColor::cmyk: + m_fillLabel->setText( i18n( "Fill: CMYK") ); break; + case VColor::hsb: + m_fillLabel->setText( i18n( "Fill: HSB") ); break; + case VColor::gray: + m_fillLabel->setText( i18n( "Fill: Grayscale") ); break; + default: + m_fillLabel->setText( i18n( "Fill: Color") ); + } + fill.setColor( f.color() ); + break; + } + case VFill::grad: + { + fill.gradient() = f.gradient(); + fill.setType( VFill::grad ); + m_fillLabel->setText( i18n( "Fill: Gradient") ); + if( f.gradient().type() == VGradient::linear ) + { + fill.gradient().setOrigin( KoPoint( m_fillFrame->width() * 0.5, 0 ) ); + fill.gradient().setVector( KoPoint( m_fillFrame->width() * 0.5, m_fillFrame->height() ) ); + } + else if( f.gradient().type() == VGradient::radial || + f.gradient().type() == VGradient::conic ) + { + fill.gradient().setOrigin( KoPoint( m_fillFrame->width() * 0.5, m_fillFrame->height() * 0.5 ) ); + fill.gradient().setFocalPoint( KoPoint( m_fillFrame->width() * 0.5, m_fillFrame->height() * 0.5 ) ); + fill.gradient().setVector( KoPoint( m_fillFrame->width() * 0.5, m_fillFrame->height() ) ); + } + break; + + } + case VFill::patt: + { + fill.pattern() = f.pattern(); + fill.pattern().setOrigin( KoPoint( 0, 0 ) ); + fill.pattern().setVector( KoPoint( m_fillFrame->width() * 0.5, 0 ) ); + fill.setType( VFill::patt ); + m_fillLabel->setText( i18n( "Fill: Pattern") ); + break; + } + default: //None or unknown + { + m_fillLabel->setText( i18n( "Fill: None") ); + fill.setColor( Qt::white ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_fillFrame->width(), m_fillFrame->height() ) ); + stroke.setColor( Qt::red ); + stroke.setLineWidth( 2.0 ); + m_painter->setPen( stroke ); + m_painter->newPath(); + m_painter->moveTo( KoPoint( 4, m_fillFrame->height() - 4 ) ); + m_painter->lineTo( KoPoint( m_fillFrame->width() - 4, 4 ) ); + m_painter->strokePath(); + } + } + + if( f.type() != VFill::none ) + { + m_painter->setPen( stroke ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_fillFrame->width(), m_fillFrame->height() ) ); + } + + m_painter->end(); + + bitBlt( m_fillFrame, m_fillFrame->frameWidth(), m_fillFrame->frameWidth(), &m_pixmap, m_fillFrame->frameWidth(), m_fillFrame->frameWidth(), m_fillFrame->width() - m_fillFrame->frameWidth(), m_fillFrame->height() - m_fillFrame->frameWidth(), CopyROP ); + + delete ( m_painter ); +} + +void +VSmallPreview::drawStroke( const VStroke &s ) +{ + VFill fill; + VStroke stroke; + + QPixmap m_pixmap; + m_pixmap.resize( m_fillFrame->width(), m_fillFrame->height() ); + VKoPainter* m_painter = new VKoPainter( &m_pixmap, m_fillFrame->width(), m_fillFrame->height() ); + + m_painter->begin(); + m_painter->setPen( Qt::NoPen ); + fill.setColor( Qt::white ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_strokeFrame->width(), m_strokeFrame->height() ) ); + + switch ( s.type() ) + { + case VStroke::solid: + { + switch ( s.color().colorSpace() ) + { + case VColor::rgb: + m_strokeLabel->setText( i18n( "Stroke: RGB") ); break; + case VColor::cmyk: + m_strokeLabel->setText( i18n( "Stroke: CMYK") ); break; + case VColor::hsb: + m_strokeLabel->setText( i18n( "Stroke: HSB") ); break; + case VColor::gray: + m_strokeLabel->setText( i18n( "Stroke: Grayscale") ); break; + default: + m_strokeLabel->setText( i18n( "Stroke: Color") ); + } + fill.setColor( s.color() ); + break; + } + case VStroke::grad: + { + fill.gradient() = s.gradient(); + fill.setType( VFill::grad ); + m_strokeLabel->setText( i18n( "Stroke: Gradient") ); + if( s.gradient().type() == VGradient::linear ) + { + fill.gradient().setOrigin( KoPoint( m_strokeFrame->width() * 0.5, 0 ) ); + fill.gradient().setVector( KoPoint( m_strokeFrame->width() * 0.5, m_strokeFrame->height() ) ); + } + else if( s.gradient().type() == VGradient::radial || + s.gradient().type() == VGradient::conic ) + { + fill.gradient().setOrigin( KoPoint( m_strokeFrame->width() * 0.5, m_strokeFrame->height() * 0.5 ) ); + fill.gradient().setFocalPoint( KoPoint( m_strokeFrame->width() * 0.5, m_strokeFrame->height() * 0.5 ) ); + fill.gradient().setVector( KoPoint( m_strokeFrame->width() * 0.5, m_strokeFrame->height() ) ); + } + break; + } + case VStroke::patt: + { + fill.pattern() = s.pattern(); + fill.pattern().setOrigin( KoPoint( 0, 0 ) ); + fill.pattern().setVector( KoPoint( m_strokeFrame->width() * 0.5, 0 ) ); + fill.setType( VFill::patt ); + m_strokeLabel->setText( i18n( "Stroke: Pattern") ); + break; + } + default: //None or unknown + { + m_strokeLabel->setText( i18n( "Stroke: None") ); + fill.setColor( Qt::white ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_strokeFrame->width(), m_strokeFrame->height() ) ); + stroke.setColor( Qt::red ); + stroke.setLineWidth( 2.0 ); + m_painter->setPen( stroke ); + m_painter->newPath(); + m_painter->moveTo( KoPoint( 4, m_strokeFrame->height() - 4 ) ); + m_painter->lineTo( KoPoint( m_strokeFrame->width() - 4, 4 ) ); + m_painter->strokePath(); + } + } + + if( s.type() != VStroke::none ) + { + m_painter->setPen( stroke ); + m_painter->setBrush( fill ); + m_painter->drawRect( KoRect( 0, 0, m_strokeFrame->width(), m_strokeFrame->height() ) ); + } + + m_painter->end(); + + bitBlt( m_strokeFrame, m_strokeFrame->frameWidth(), m_strokeFrame->frameWidth(), &m_pixmap, m_strokeFrame->frameWidth(), m_strokeFrame->frameWidth(), m_strokeFrame->width() - m_strokeFrame->frameWidth(), m_strokeFrame->height() - m_strokeFrame->frameWidth(), CopyROP ); + + delete ( m_painter ); +} + +#include "vsmallpreview.moc" + diff --git a/karbon/widgets/vsmallpreview.h b/karbon/widgets/vsmallpreview.h new file mode 100644 index 00000000..7b1abb15 --- /dev/null +++ b/karbon/widgets/vsmallpreview.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.t-com.hr) + Copyright (C) 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +/* This is a small widget used on the statusbar, to display fill/stroke colors etc. */ + +/* vsmallpreview.h */ +#ifndef VSMALLPREVIEW_H +#define VSMALLPREVIEW_H + +#include <qwidget.h> + +class QFrame; +class QLabel; +class VFill; +class VStroke; + +class VSmallPreview : public QWidget +{ + Q_OBJECT +public: + VSmallPreview( QWidget* parent = 0L, const char* name = 0L ); + ~VSmallPreview(); + + void update( const VStroke &, const VFill & ); + +protected: + virtual void paintEvent( QPaintEvent* event ); + +private: + void drawFill( const VFill & ); + void drawStroke( const VStroke & ); + QFrame *m_fillFrame; + QFrame *m_strokeFrame; + QLabel *m_fillLabel; + QLabel *m_strokeLabel; + VFill m_fill; + VStroke m_stroke; +}; + +#endif + diff --git a/karbon/widgets/vstatebutton.cc b/karbon/widgets/vstatebutton.cc new file mode 100644 index 00000000..635d3de7 --- /dev/null +++ b/karbon/widgets/vstatebutton.cc @@ -0,0 +1,49 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vstatebutton.h" + +VStateButton::VStateButton( QWidget* parent, const char* name ) + : QPushButton( parent, name ) +{ + m_index = 0; + m_pixmaps.setAutoDelete( true ); +} + +VStateButton::~VStateButton() +{ +} + +void +VStateButton::mouseReleaseEvent( QMouseEvent *e ) +{ + QPushButton::mouseReleaseEvent( e ); + if( m_pixmaps.count() > 0 ) + { + m_index = ++m_index % m_pixmaps.count(); + setPixmap( *( m_pixmaps.at( m_index ) ) ); + } +} + +void +VStateButton::setState( unsigned int /*index*/ ) +{ + if( m_pixmaps.count() > 0 ) + setPixmap( *( m_pixmaps.at( m_index ) ) ); +} diff --git a/karbon/widgets/vstatebutton.h b/karbon/widgets/vstatebutton.h new file mode 100644 index 00000000..6273adcc --- /dev/null +++ b/karbon/widgets/vstatebutton.h @@ -0,0 +1,45 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTATEBUTTON_H__ +#define __VSTATEBUTTON_H__ + +#include <qpushbutton.h> +#include <qpixmap.h> +#include <qptrlist.h> + +class VStateButton : public QPushButton +{ +public: + VStateButton( QWidget* parent = 0L, const char* name = 0L ); + ~VStateButton(); + + void addState( QPixmap *state ) { m_pixmaps.append( state ); } + void setState( unsigned int index ); + unsigned int getState() const { return m_index; } + +private: + void mouseReleaseEvent( QMouseEvent * ); + + QPtrList<QPixmap> m_pixmaps; + unsigned int m_index; +}; + +#endif + diff --git a/karbon/widgets/vstrokefillpreview.cc b/karbon/widgets/vstrokefillpreview.cc new file mode 100644 index 00000000..40dbe4d6 --- /dev/null +++ b/karbon/widgets/vstrokefillpreview.cc @@ -0,0 +1,451 @@ +/* This file is part of the KDE project + Copyright (C) 2002 - 2005, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcolor.h> + +#include <kdebug.h> +#include <KoPoint.h> + +#include "karbon_part.h" +#include "vcolordlg.h" +#include "vfill.h" +#include "vfillcmd.h" +#include "vkopainter.h" +#include "vselection.h" +#include "vstroke.h" +#include "vstrokecmd.h" +#include "vstrokefillpreview.h" + +#define PANEL_SIZEX 50.0 +#define PANEL_SIZEY 50.0 + +#define FILL_TOPX 15.0 +#define FILL_TOPY 15.0 +#define FILL_BOTTOMX 45.0 +#define FILL_BOTTOMY 45.0 + +#define STROKE_TOPX 5.0 +#define STROKE_TOPY 5.0 +#define STROKE_BOTTOMX 35.0 +#define STROKE_BOTTOMY 35.0 + +#define STROKE_TOPX_INNER STROKE_TOPX + 4 +#define STROKE_TOPY_INNER STROKE_TOPY + 4 +#define STROKE_BOTTOMX_INNER STROKE_BOTTOMX - 4 +#define STROKE_BOTTOMY_INNER STROKE_BOTTOMY - 4 + + +VStrokeFillPreview::VStrokeFillPreview( + KarbonPart *part, QWidget* parent, const char* name ) + : QFrame( parent, name ), m_part( part ) +{ + m_strokeWidget = false; + setFocusPolicy( QWidget::NoFocus ); + +#if QT_VERSION < 0x030100 + setFrameStyle( QFrame::Panel | QFrame::Sunken ); +#else + setFrameStyle( QFrame::GroupBoxPanel | QFrame::Sunken ); +#endif + + installEventFilter( this ); + m_pixmap.resize( int( PANEL_SIZEX ), int( PANEL_SIZEY ) ); + m_painter = new VKoPainter( &m_pixmap, uint( PANEL_SIZEX ), uint( PANEL_SIZEY ) ); +} + +VStrokeFillPreview::~VStrokeFillPreview() +{ + delete( m_painter ); +} + +void +VStrokeFillPreview::paintEvent( QPaintEvent* event ) +{ + bitBlt( this, + (int)( width() - PANEL_SIZEX ) / 2, (int)( height() - PANEL_SIZEY ) / 2, + &m_pixmap, + 0, 0, (int)PANEL_SIZEX, (int)PANEL_SIZEY ); + + QFrame::paintEvent( event ); +} + +bool +VStrokeFillPreview::eventFilter( QObject *, QEvent *event ) +{ + QMouseEvent* e = static_cast<QMouseEvent *>( event ); + + int ex = e->x() - int( ( width() - PANEL_SIZEX ) / 2 ); + int ey = e->y() - int( ( height() - PANEL_SIZEY ) / 2 ); + + if( event && event->type() == QEvent::MouseButtonPress ) + { + if ( m_strokeWidget ) + { + if( + ex >= STROKE_TOPX && ex <= STROKE_BOTTOMX && + ey >= STROKE_TOPY && ey <= STROKE_BOTTOMY ) + { + m_strokeWidget = true; + emit strokeSelected(); + } + else if( + ex >= FILL_TOPX && ex <= FILL_BOTTOMX && + ey >= FILL_TOPY && ey <= FILL_BOTTOMY ) + { + m_strokeWidget = false; + emit fillSelected(); + } + } + else + { + if( + ex >= FILL_TOPX && ex <= FILL_BOTTOMX && + ey >= FILL_TOPY && ey <= FILL_BOTTOMY ) + { + m_strokeWidget = false; + emit fillSelected(); + } + else if( + ex >= STROKE_TOPX && ex <= STROKE_BOTTOMX && + ey >= STROKE_TOPY && ey <= STROKE_BOTTOMY ) + { + m_strokeWidget = true; + emit strokeSelected(); + } + } + update( m_stroke, m_fill ); + } + + if( event && event->type() == QEvent::MouseButtonDblClick ) + { + if( + ex >= FILL_TOPX && ex <= FILL_BOTTOMX && + ey >= FILL_TOPY && ey <= FILL_BOTTOMY ) + { + VColorDlg* dialog = new VColorDlg( m_fill.color(), this ); + if( dialog->exec() == QDialog::Accepted ) + { + if( m_part && m_part->document().selection() ) m_part->addCommand( new VFillCmd( &m_part->document(), VFill( dialog->Color() ) ), true ); + } + delete dialog; + } + else if( + ex >= STROKE_TOPX && ex <= STROKE_BOTTOMX + && ey >= STROKE_TOPY && ey <= STROKE_BOTTOMY ) + { + VColorDlg* dialog = new VColorDlg( m_stroke.color(), this ); + if( dialog->exec() == QDialog::Accepted ) + { + if( m_part && m_part->document().selection() ) m_part->addCommand( new VStrokeCmd( &m_part->document(), dialog->Color() ), true ); + } + delete dialog; + } + } + return false; +} + +void +VStrokeFillPreview::update( const VStroke &s, const VFill &f ) +{ + m_painter->begin(); + + if( &f ) + m_fill = f; + else + m_fill = VFill(); + if( &s ) + m_stroke = s; + else + m_stroke = VStroke(); + + // draw checkerboard + VFill fill; + m_painter->setPen( Qt::NoPen ); + + for( unsigned char y = 0; y < PANEL_SIZEY; y += 10 ) + for( unsigned char x = 0; x < PANEL_SIZEX; x += 10 ) + { + fill.setColor( ( ( ( x + y ) % 20 ) == 0 ) ? QColor( 180, 180, 180 ) : QColor( 100, 100, 100 ) ); + m_painter->setBrush( fill ); + m_painter->drawRect( x, y, 10, 10 ); + } + + if ( m_strokeWidget ) + { + drawFill( m_fill ); + drawStroke( m_stroke ); + } + else + { + drawStroke( m_stroke ); + drawFill( m_fill ); + } + + m_painter->end(); + + repaint(); +} + +void +VStrokeFillPreview::drawFill( const VFill &f ) +{ + VStroke stroke; + + if( f.type() != VFill::none ) + { + if( f.type() != VFill::solid ) + { + VFill fill; + fill = f; + + if( f.type() == VFill::grad ) + { + if( f.gradient().type() == VGradient::linear ) + { + fill.gradient().setOrigin( KoPoint( 30, 20 ) ); + fill.gradient().setVector( KoPoint( 30, 50 ) ); + } + else if( f.gradient().type() == VGradient::radial || + f.gradient().type() == VGradient::conic ) + { + fill.gradient().setOrigin( KoPoint( 30, 35 ) ); + fill.gradient().setFocalPoint( KoPoint( 30, 35 ) ); + fill.gradient().setVector( KoPoint( 30, 50 ) ); + } + } + if( f.type() == VFill::patt ) + { + fill.pattern() = f.pattern(); + fill.pattern().setOrigin( KoPoint( 20, 10 ) ); + fill.pattern().setVector( KoPoint( 30, 10 ) ); + fill.setType( VFill::patt ); + } + + m_painter->setBrush( fill ); + } + else + m_painter->setBrush( f ); + m_painter->setPen( Qt::NoPen ); + m_painter->drawRect( KoRect( FILL_TOPX, FILL_TOPY, FILL_BOTTOMX - FILL_TOPX, FILL_BOTTOMY - FILL_TOPY ) ); + } + else + { + VFill fill; + fill.setColor( Qt::white ); + m_painter->setBrush( fill ); + m_painter->setPen( Qt::NoPen ); + + m_painter->drawRect( KoRect( FILL_TOPX, FILL_TOPY, + FILL_BOTTOMX - FILL_TOPX, + FILL_BOTTOMY - FILL_TOPY ) ); + } + + // show 3D outline of fill part + VColor color; + + m_painter->setBrush( Qt::NoBrush ); + color.set( 1.0, 1.0, 1.0 ); + stroke.setColor( color ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( FILL_BOTTOMX, FILL_TOPY ) ); + m_painter->lineTo( KoPoint( FILL_TOPX, FILL_TOPY ) ); + m_painter->lineTo( KoPoint( FILL_TOPX, FILL_BOTTOMY ) ); + m_painter->strokePath(); + + color.set( 0.5, 0.5, 0.5 ); + stroke.setColor( color ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( FILL_BOTTOMX, FILL_TOPY ) ); + m_painter->lineTo( KoPoint( FILL_BOTTOMX, FILL_BOTTOMY ) ); + m_painter->lineTo( KoPoint( FILL_TOPX, FILL_BOTTOMY ) ); + m_painter->strokePath(); + + if( f.type() == VFill::none ) + { + stroke.setColor( Qt::red ); + m_painter->setPen( stroke ); + m_painter->newPath(); + m_painter->moveTo( KoPoint( FILL_BOTTOMX, FILL_TOPY ) ); + m_painter->lineTo( KoPoint( FILL_TOPX, FILL_BOTTOMY ) ); + m_painter->strokePath(); + } +} + +void +VStrokeFillPreview::drawStroke( const VStroke &s ) +{ + VStroke stroke; + stroke.setLineWidth( 2.0 ); + + m_painter->setPen( Qt::NoPen ); + + if( s.type() != VStroke::none ) + { + VFill fill; + + if( s.type() != VStroke::solid ) + { + if( s.type() == VStroke::grad ) + { + fill.gradient() = s.gradient(); + + if( s.gradient().type() == VGradient::linear ) + { + fill.gradient().setOrigin( KoPoint( FILL_TOPX, 10 ) ); + fill.gradient().setVector( KoPoint( FILL_TOPX, 40 ) ); + } + else if( s.gradient().type() == VGradient::radial || + s.gradient().type() == VGradient::conic ) + { + fill.gradient().setOrigin( KoPoint( FILL_TOPX, 25 ) ); + fill.gradient().setFocalPoint( KoPoint( FILL_TOPX, 25 ) ); + fill.gradient().setVector( KoPoint( FILL_TOPX, 40 ) ); + } + + fill.setType( VFill::grad ); + } + if( s.type() == VStroke::patt ) + { + fill.pattern() = s.pattern(); + fill.pattern().setOrigin( KoPoint( FILL_TOPX, 10 ) ); + fill.pattern().setVector( KoPoint( FILL_TOPX, 40 ) ); + fill.setType( VFill::patt ); + } + } + else + fill.setColor( s.color() ); + + m_painter->setFillRule( evenOdd ); + + m_painter->setBrush( fill ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_TOPX, STROKE_TOPY ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX, STROKE_TOPY ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX, STROKE_BOTTOMY ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX, STROKE_BOTTOMY ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX, STROKE_TOPY ) ); + + m_painter->moveTo( KoPoint( STROKE_TOPX_INNER, STROKE_TOPY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX_INNER, STROKE_TOPY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX_INNER, STROKE_BOTTOMY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER, STROKE_BOTTOMY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER, STROKE_TOPY_INNER ) ); + m_painter->fillPath(); + } + else + { + VFill fill; + m_painter->setFillRule( evenOdd ); + fill.setColor( Qt::white ); + + m_painter->setBrush( fill ); + m_painter->setPen( Qt::NoPen ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_TOPX, STROKE_TOPY ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX, STROKE_TOPY ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX, STROKE_BOTTOMY ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX, STROKE_BOTTOMY ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX, STROKE_TOPY ) ); + + m_painter->moveTo( KoPoint( STROKE_TOPX_INNER, STROKE_TOPY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX_INNER, STROKE_TOPY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX_INNER, STROKE_BOTTOMY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER, STROKE_BOTTOMY_INNER ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER, STROKE_TOPY_INNER ) ); + m_painter->fillPath(); + } + + // show 3D outline of stroke part + VColor color; + + color.set( 1.0, 1.0, 1.0 ); + stroke.setColor( color ); + m_painter->setBrush( Qt::NoBrush ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_BOTTOMX + 1, STROKE_TOPY - 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX - 1, STROKE_TOPY - 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX - 1, STROKE_BOTTOMY + 1 ) ); + m_painter->strokePath(); + + color.set( 0.5, 0.5, 0.5 ); + stroke.setColor( color ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_BOTTOMX + 1, STROKE_TOPY - 1 ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX + 1, STROKE_BOTTOMY + 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX - 1, STROKE_BOTTOMY + 1 ) ); + m_painter->strokePath(); + + //stroke.setColor( Qt::black.rgb() ); + //m_painter->setPen( stroke ); + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_BOTTOMX_INNER - 1, STROKE_TOPY_INNER + 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER + 1, STROKE_TOPY_INNER + 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER + 1, STROKE_BOTTOMY_INNER - 1 ) ); + m_painter->strokePath(); + + color.set( 1.0, 1.0, 1.0 ); + stroke.setColor( color ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_BOTTOMX_INNER - 1, STROKE_TOPY_INNER + 1 ) ); + m_painter->lineTo( KoPoint( STROKE_BOTTOMX_INNER - 1, STROKE_BOTTOMY_INNER - 1 ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX_INNER + 1, STROKE_BOTTOMY_INNER - 1 ) ); + m_painter->strokePath(); + + if( s.type() == VStroke::none ) + { + stroke.setColor( Qt::red ); + m_painter->setPen( stroke ); + + m_painter->newPath(); + m_painter->moveTo( KoPoint( STROKE_BOTTOMX, STROKE_TOPY ) ); + m_painter->lineTo( KoPoint( STROKE_TOPX, STROKE_BOTTOMY ) ); + m_painter->strokePath(); + } +} + +void +VStrokeFillPreview::setFillSelected() +{ + m_strokeWidget = false; + update( m_stroke, m_fill ); + emit fillSelected(); +} + +void +VStrokeFillPreview::setStrokeSelected() +{ + m_strokeWidget = true; + update( m_stroke, m_fill ); + emit strokeSelected(); +} + +#include "vstrokefillpreview.moc" + diff --git a/karbon/widgets/vstrokefillpreview.h b/karbon/widgets/vstrokefillpreview.h new file mode 100644 index 00000000..20b0acbd --- /dev/null +++ b/karbon/widgets/vstrokefillpreview.h @@ -0,0 +1,74 @@ +/* This file is part of the KDE project + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSTROKEFILLPREVIEW_H__ +#define __VSTROKEFILLPREVIEW_H__ + +#include <qframe.h> +#include <qpixmap.h> + +class VKoPainter; +class VFill; +class VStroke; +class KarbonPart; + +class VStrokeFillPreview : public QFrame +{ + Q_OBJECT + +public: + VStrokeFillPreview( KarbonPart *part, QWidget* parent = 0L, const char* name = 0L ); + ~VStrokeFillPreview(); + + virtual QSize sizeHint() const + { return QSize( 50, 50 ); } + virtual QSize minimumSizeHint() const + { return QSize( 20, 20 ); } + virtual QSizePolicy sizePolicy() const + { return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); } + + void update( const VStroke &, const VFill & ); + + virtual bool eventFilter( QObject* object, QEvent* event ); + + bool strokeIsSelected() const { return m_strokeWidget; } + void setFillSelected(); + void setStrokeSelected(); +signals: + void strokeChanged( const VStroke & ); + void fillChanged( const VFill& ); + void fillSelected(); + void strokeSelected(); + +protected: + virtual void paintEvent( QPaintEvent* event ); + +private: + VKoPainter* m_painter; + void drawFill( const VFill & ); + void drawStroke( const VStroke & ); + QPixmap m_pixmap; + KarbonPart *m_part; + bool m_strokeWidget; + VFill m_fill; + VStroke m_stroke; +}; + +#endif + diff --git a/karbon/widgets/vtoolbox.cc b/karbon/widgets/vtoolbox.cc new file mode 100644 index 00000000..6146ae93 --- /dev/null +++ b/karbon/widgets/vtoolbox.cc @@ -0,0 +1,42 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "vtoolbox.h" +#include "vtool.h" + +VToolBox::VToolBox( KMainWindow *mainWin, const char* name, KInstance* instance ) : KoToolBox( mainWin, name, instance, 5 ) +{ +} + +void +VToolBox::registerTool( VTool *tool ) +{ + kdDebug(38000) << "VToolBox::registerTool : " << tool->name() << endl; + KoToolBox::registerTool( tool->action(), tool->toolType(), tool->priority() ); +} + +void +VToolBox::setupTools() +{ + kdDebug(38000) << k_funcinfo << endl; + KoToolBox::setupTools(); +} + +#include "vtoolbox.moc" diff --git a/karbon/widgets/vtoolbox.h b/karbon/widgets/vtoolbox.h new file mode 100644 index 00000000..28c53f97 --- /dev/null +++ b/karbon/widgets/vtoolbox.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTOOLBOX_H__ +#define __VTOOLBOX_H__ +#include <KoToolBox.h> +class VTool; + +/// This class... + +class VToolBox : public KoToolBox +{ + Q_OBJECT + +public: + VToolBox( KMainWindow *mainWin, const char* name, KInstance* instance ); + virtual ~VToolBox() {} + + void registerTool( VTool * ); + void setupTools(); + +signals: + void activeToolChanged( VTool * ); +}; + +#endif + diff --git a/karbon/widgets/vtranslate.cc b/karbon/widgets/vtranslate.cc new file mode 100644 index 00000000..1eaf81ed --- /dev/null +++ b/karbon/widgets/vtranslate.cc @@ -0,0 +1,84 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qstring.h> +#include <klocale.h> +#include <knuminput.h> +#include <kstdguiitem.h> +#include <kpushbutton.h> + +#include "vtranslate.h" + +VTranslate::VTranslate( QWidget* parent, const char* name ) + : QWidget( parent, name ) +{ + setCaption( i18n( "Translate" ) ); + + QVBoxLayout *mainlayout = new QVBoxLayout(this, 7); + mainlayout->addSpacing(5); + + QGridLayout *inputlayout = new QGridLayout(this, 5, 3); + mainlayout->addLayout(inputlayout); + m_labelX = new QLabel(i18n("X:"), this); + inputlayout->addWidget(m_labelX, 0, 0); + labely = new QLabel(i18n("Y:"), this); + inputlayout->addWidget(labely, 1, 0); + inputlayout->addColSpacing(1, 1); + inputlayout->addColSpacing(3, 5); + m_inputX = new KDoubleNumInput( this ); + m_inputX->setRange(-10000.00, 10000.00, 1.00, false); //range is just for example - for now :-) + inputlayout->addWidget(m_inputX, 0, 2); + m_inputY = new KDoubleNumInput( this ); + m_inputY->setRange(-10000.00, 10000.00, 1.00, false); + inputlayout->addWidget(m_inputY, 1, 2); + m_labelUnit1 = new QLabel("", this); + inputlayout->addWidget(m_labelUnit1, 0, 4); + m_labelUnit2 = new QLabel("", this); + inputlayout->addWidget(m_labelUnit2, 1, 4); + mainlayout->addSpacing(5); + m_checkBoxPosition = new QCheckBox(i18n("Relative &position"), this); + mainlayout->addWidget(m_checkBoxPosition); + mainlayout->addSpacing(5); + m_buttonDuplicate = new QPushButton(i18n("&Duplicate"), this); + mainlayout->addWidget(m_buttonDuplicate); + mainlayout->addSpacing(1); + m_buttonApply = new KPushButton(KStdGuiItem::apply(), this); + mainlayout->addWidget(m_buttonApply); + + mainlayout->activate(); + + setFixedSize(baseSize()); //Set the size tp fixed values +} + +VTranslate::~VTranslate() +{ +} + +void VTranslate::setUnits( const QString& units ) +{ + m_labelUnit1->setText( units ); + m_labelUnit2->setText( units ); +} + +#include "vtranslate.moc" + diff --git a/karbon/widgets/vtranslate.h b/karbon/widgets/vtranslate.h new file mode 100644 index 00000000..23fd1325 --- /dev/null +++ b/karbon/widgets/vtranslate.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) + Copyright (C) 2002, The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTRANSLATE_H__ +#define __VTRANSLATE_H__ + +#include <qwidget.h> + +class QCheckBox; +class QLabel; +class QPushButton; +class QString; +class KDoubleNumInput; + +class VTranslate : public QWidget +{ + Q_OBJECT + +public: + VTranslate( QWidget* parent = 0L, const char* name = 0L ); + ~VTranslate(); + +public slots: + //sets the unit labels do display correct text (mm, cm, pixels etc): + void setUnits( const QString& units ); + +private: + QLabel* m_labelX; + KDoubleNumInput* m_inputX; //X coordinate + QLabel* labely; + KDoubleNumInput* m_inputY; //Y coordinate + QLabel* m_labelUnit1; + QLabel* m_labelUnit2; + QCheckBox* m_checkBoxPosition; //If checked, displays coordinates of selected object + QPushButton* m_buttonDuplicate; //duplicate (makes a copy of selected object(s) with a new position) + QPushButton* m_buttonApply; //apply new position +}; + +#endif + diff --git a/karbon/widgets/vtypebuttonbox.cc b/karbon/widgets/vtypebuttonbox.cc new file mode 100644 index 00000000..4a23d6dd --- /dev/null +++ b/karbon/widgets/vtypebuttonbox.cc @@ -0,0 +1,330 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#if 0 + +// 8x8 pixels + +static const char* const buttonnone[]={ +"8 8 7 1", +"c c #0a0000", +". c #0a0a0a", +"b c #330000", +"a c #331f1f", +"# c #333333", +"e c #ff0000", +"d c #ffffff", +".####abc", +"#ddddeeb", +"#dddeeea", +"#ddeeed#", +"#deeedd#", +"aeeeddd#", +"beedddd#", +"cba####."}; + +static const char* const buttonsolid[]={ +"8 8 1 1", +". c #000000", +"........", +"........", +"........", +"........", +"........", +"........", +"........", +"........"}; + +static const char* const buttongradient[]={ +"8 8 14 1", +"f c #000000", +"e c #040404", +". c #0a0a0a", +"d c #0f0f0f", +"c c #181818", +"b c #212121", +"a c #292929", +"# c #303030", +"g c #333333", +"l c #484848", +"k c #787878", +"j c #a7a7a7", +"i c #cdcdcd", +"h c #f1f1f1", +".#abcdef", +"ghijkl#f", +"ghijkl#f", +"ghijkl#f", +"ghijkl#f", +"ghijkl#f", +"ghijkl#f", +".#abcdef"}; + +static const char* const buttonpattern[]={ +"8 8 4 1", +". c #0a0a0a", +"# c #333333", +"a c #a0a0a0", +"b c #ffffff", +".######.", +"#aabbaa#", +"#aabbaa#", +"#bbaabb#", +"#bbaabb#", +"#aabbaa#", +"#aabbaa#", +".######."}; + +#else + +// 16x16 pixels + +static const char* const buttonnone[]={ +"16 16 7 1", +"c c #0a0000", +". c #0a0a0a", +"b c #330000", +"a c #331f1f", +"# c #333333", +"e c #ff0000", +"d c #ffffff", +"..########aabbcc", +"..########aabbcc", +"##dddddddddeeebb", +"##ddddddddeeeebb", +"##dddddddeeeeeaa", +"##ddddddeeeeedaa", +"##dddddeeeeedd##", +"##ddddeeeeeddd##", +"##dddeeeeedddd##", +"##ddeeeeeddddd##", +"aaeeeeeedddddd##", +"aaeeeeeddddddd##", +"bbeeeedddddddd##", +"bbeeeddddddddd##", +"ccbbaa########..", +"ccbbaa########.."}; + +static const char* const buttonsolid[]={ +"16 16 1 1", +". c #000000", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................"}; + + +// FIXME: Smoother gradient button. + +static const char* const buttongradient[]={ +"16 16 14 1", +"f c #000000", +"e c #040404", +". c #0a0a0a", +"d c #0f0f0f", +"c c #181818", +"b c #212121", +"a c #292929", +"# c #303030", +"g c #333333", +"l c #484848", +"k c #787878", +"j c #a7a7a7", +"i c #cdcdcd", +"h c #f1f1f1", +"..##aabbccddeeff", +"..##aabbccddeeff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"gghhiijjkkll##ff", +"..##aabbccddeeff", +"..##aabbccddeeff"}; + +static const char* const buttonpattern[]={ +"16 16 4 1", +". c #0a0a0a", +"# c #333333", +"a c #a0a0a0", +"b c #ffffffff", +"..############..", +"..############..", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"##bbbbaaaabbbb##", +"##bbbbaaaabbbb##", +"##bbbbaaaabbbb##", +"##bbbbaaaabbbb##", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"##aaaabbbbaaaa##", +"..############..", +"..############.."}; + +#endif + + +#include <qpixmap.h> +#include <qtoolbutton.h> +#include <qtooltip.h> + +#include <klocale.h> + +#include "karbon_part.h" +#include "vfillcmd.h" +#include "vselection.h" +#include "vstrokecmd.h" + +#include "vtypebuttonbox.h" + +VTypeButtonBox::VTypeButtonBox( KarbonPart *part, + QWidget* parent, const char* name ) + : QHButtonGroup( parent, name ), + m_part( part ), m_isStrokeManipulator( false ) +{ + setMaximumWidth( parent->width() - 2 ); + + // The button for no fill + QToolButton* button = new QToolButton( this ); + button->setPixmap( QPixmap( (const char **) buttonnone ) ); + button->setMaximumWidth( 14 ); + button->setMaximumHeight( 14 ); + QToolTip::add( button, i18n( "None" ) ); + insert( button, none ); + + // The button for solid fill + button = new QToolButton( this ); + button->setPixmap( QPixmap( (const char **) buttonsolid ) ); + button->setMaximumWidth( 14 ); + button->setMaximumHeight( 14 ); + QToolTip::add( button, i18n( "Solid" ) ); + insert( button, solid ); + + // The button for gradient fill + button = new QToolButton( this ); + button->setPixmap( QPixmap( (const char **) buttongradient ) ); + button->setMaximumWidth( 14 ); + button->setMaximumHeight( 14 ); + QToolTip::add( button, i18n( "Gradient" ) ); + insert( button, gradient ); + + // The button for pattern fill + button = new QToolButton( this ); + button->setPixmap( QPixmap( (const char **) buttonpattern ) ); + button->setMaximumWidth( 14 ); + button->setMaximumHeight( 14 ); + QToolTip::add( button, i18n( "Pattern" ) ); + insert( button, pattern ); + + setInsideMargin( 1 ); + setInsideSpacing( 1 ); + connect( this, SIGNAL( clicked( int ) ), + this, SLOT( slotButtonPressed( int ) ) ); +} + +void +VTypeButtonBox::slotButtonPressed( int id ) +{ + if( m_part && m_part->document().selection()->objects().count() > 0 ) { + if ( m_isStrokeManipulator ) + manipulateStrokes( id ); + else + manipulateFills( id ); + } +} + +void +VTypeButtonBox::setStroke() +{ + m_isStrokeManipulator = true; +} + +void +VTypeButtonBox::setFill() +{ + m_isStrokeManipulator = false; +} + +void +VTypeButtonBox::manipulateFills( int id ) +{ + VFill m_fill; + m_fill = *m_part->document().selection()->objects().getFirst()->fill(); + switch( id ){ + case none: + m_fill.setType( VFill::none ); + break; + case solid: + m_fill.setType( VFill::solid ); + break; + case gradient: + m_fill.setType( VFill::grad ); + break; + case pattern: + m_fill.setType( VFill::patt ); + } + m_part->addCommand( new VFillCmd( &m_part->document(), m_fill ), true ); +} + +void +VTypeButtonBox::manipulateStrokes( int id ) +{ + VStroke m_stroke; + m_stroke = *m_part->document().selection()->objects().getFirst()->stroke(); + switch( id ){ + case none: + m_stroke.setType( VStroke::none ); + break; + case solid: + m_stroke.setType( VStroke::solid ); + break; + case gradient: + m_stroke.setType( VStroke::grad ); + break; + case pattern: + m_stroke.setType( VStroke::patt ); + } + m_part->addCommand( new VStrokeCmd( &m_part->document(), &m_stroke ), true ); +} + +#include "vtypebuttonbox.moc" + diff --git a/karbon/widgets/vtypebuttonbox.h b/karbon/widgets/vtypebuttonbox.h new file mode 100644 index 00000000..ab624c04 --- /dev/null +++ b/karbon/widgets/vtypebuttonbox.h @@ -0,0 +1,56 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + 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; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VTYPEBUTTONBOX_H__ +#define __VTYPEBUTTONBOX_H__ + +#include <qhbuttongroup.h> + +class KarbonPart; + +class VTypeButtonBox : public QHButtonGroup +{ + Q_OBJECT + +public: + enum buttonType { + none = 0, + solid = 1, + gradient = 2, + pattern = 3 + }; + + VTypeButtonBox( KarbonPart *part, QWidget* parent = 0L, const char* name = 0L ); + bool isStrokeManipulator() { return m_isStrokeManipulator; } + +public slots: + void slotButtonPressed( int id ); + void setFill(); + void setStroke(); + +private: + KarbonPart *m_part; + bool m_isStrokeManipulator; + + void manipulateFills( int id ); + void manipulateStrokes( int id ); +}; + +#endif + |